eve 0.25.3 → 0.26.0
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/CHANGELOG.md +23 -0
- package/dist/src/chunks/{use-eve-agent-Cy73lgA6.js → use-eve-agent-BkztZA0v.js} +76 -55
- package/dist/src/chunks/{use-eve-agent-CQIeqmKc.js → use-eve-agent-CruinZmd.js} +76 -55
- package/dist/src/cli/commands/logs-events.d.ts +36 -0
- package/dist/src/cli/commands/logs-events.js +2 -0
- package/dist/src/cli/commands/logs.d.ts +64 -0
- package/dist/src/cli/commands/logs.js +4 -0
- package/dist/src/cli/dev/diagnostic-dump.d.ts +60 -0
- package/dist/src/cli/dev/diagnostic-dump.js +1 -0
- package/dist/src/cli/dev/diagnostic-sink.d.ts +37 -0
- package/dist/src/cli/dev/diagnostic-sink.js +1 -0
- package/dist/src/cli/dev/diagnostics.d.ts +42 -0
- package/dist/src/cli/dev/diagnostics.js +1 -0
- package/dist/src/cli/dev/tui/blocks.d.ts +4 -0
- package/dist/src/cli/dev/tui/blocks.js +7 -7
- package/dist/src/cli/dev/tui/command-typeahead.js +1 -1
- package/dist/src/cli/dev/tui/diagnostic-presentation.d.ts +14 -0
- package/dist/src/cli/dev/tui/diagnostic-presentation.js +2 -0
- package/dist/src/cli/dev/tui/errors.d.ts +21 -16
- package/dist/src/cli/dev/tui/errors.js +1 -1
- package/dist/src/cli/dev/tui/line-editor.js +1 -1
- package/dist/src/cli/dev/tui/markdown.js +1 -1
- package/dist/src/cli/dev/tui/model-editor.d.ts +103 -0
- package/dist/src/cli/dev/tui/model-editor.js +1 -0
- package/dist/src/cli/dev/tui/prompt-command-handler.d.ts +1 -1
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
- package/dist/src/cli/dev/tui/remote-auth-command.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +5 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/cli/dev/tui/setup-flow.d.ts +3 -0
- package/dist/src/cli/dev/tui/setup-panel.d.ts +33 -0
- package/dist/src/cli/dev/tui/setup-panel.js +4 -4
- package/dist/src/cli/dev/tui/status-line.d.ts +8 -6
- package/dist/src/cli/dev/tui/status-line.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +3 -0
- package/dist/src/cli/dev/tui/terminal-renderer.js +11 -10
- package/dist/src/cli/dev/tui/test/fake-setup-flow-renderer.js +1 -1
- package/dist/src/cli/dev/tui/theme.d.ts +14 -0
- package/dist/src/cli/dev/tui/theme.js +1 -1
- package/dist/src/cli/dev/tui/tool-format.js +1 -1
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/run.js +2 -2
- package/dist/src/cli/ui/live-row.js +1 -1
- package/dist/src/client/agent-info-schema.d.ts +9 -0
- package/dist/src/client/agent-info-schema.js +1 -1
- package/dist/src/client/client.js +1 -1
- package/dist/src/client/eve-agent-store.d.ts +1 -2
- package/dist/src/client/eve-agent-store.js +1 -1
- package/dist/src/client/open-stream.d.ts +14 -10
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session-utils.d.ts +2 -1
- package/dist/src/client/session-utils.js +1 -1
- package/dist/src/client/session.d.ts +3 -5
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/types.d.ts +0 -6
- package/dist/src/compiler/extension-compatibility.d.ts +2 -2
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-cli.d.ts +4 -0
- package/dist/src/execution/sandbox/bindings/docker-cli.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-create.js +1 -1
- package/dist/src/execution/terminal-session-failure-step.js +1 -1
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/model-call-error.d.ts +11 -30
- package/dist/src/harness/model-call-error.js +1 -1
- package/dist/src/harness/semantic-errors/index.d.ts +9 -0
- package/dist/src/harness/semantic-errors/index.js +1 -0
- package/dist/src/harness/semantic-errors/rule.d.ts +76 -0
- package/dist/src/harness/semantic-errors/rule.js +1 -0
- package/dist/src/harness/semantic-errors/rules/gateway.d.ts +11 -0
- package/dist/src/harness/semantic-errors/rules/gateway.js +1 -0
- package/dist/src/harness/semantic-errors/rules/model-provider.d.ts +11 -0
- package/dist/src/harness/semantic-errors/rules/model-provider.js +1 -0
- package/dist/src/harness/semantic-errors/rules/sandbox.d.ts +16 -0
- package/dist/src/harness/semantic-errors/rules/sandbox.js +1 -0
- package/dist/src/harness/semantic-errors/rules/system.d.ts +2 -0
- package/dist/src/harness/semantic-errors/rules/system.js +1 -0
- package/dist/src/harness/semantic-errors/rules/workflow.d.ts +9 -0
- package/dist/src/harness/semantic-errors/rules/workflow.js +1 -0
- package/dist/src/harness/semantic-errors/signals.d.ts +28 -0
- package/dist/src/harness/semantic-errors/signals.js +1 -0
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/workflow-sandbox.d.ts +6 -0
- package/dist/src/harness/workflow-sandbox.js +2 -2
- package/dist/src/internal/application/output-publication-lock.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/logging.d.ts +33 -1
- package/dist/src/internal/logging.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +3 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
- package/dist/src/internal/workflow/development-world-client.js +1 -1
- package/dist/src/internal/workflow/development-world-server.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/models/openai/chatgpt/model.js +3 -1
- package/dist/src/react/use-eve-agent.d.ts +0 -1
- package/dist/src/react/use-eve-agent.js +1 -1
- package/dist/src/setup/boxes/add-channels.js +1 -1
- package/dist/src/setup/boxes/deploy-project.js +1 -1
- package/dist/src/setup/boxes/model-capabilities.d.ts +24 -0
- package/dist/src/setup/boxes/model-capabilities.js +1 -0
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/boxes/select-model.d.ts +30 -8
- package/dist/src/setup/boxes/select-model.js +1 -1
- package/dist/src/setup/cli/option-row.js +1 -1
- package/dist/src/setup/cli/prompt-ui.d.ts +2 -0
- package/dist/src/setup/cli/prompt-ui.js +2 -2
- package/dist/src/setup/cli/rail-log.d.ts +4 -6
- package/dist/src/setup/cli/rail-log.js +3 -2
- package/dist/src/setup/connection-connector.js +2 -2
- package/dist/src/setup/flows/login.js +1 -1
- package/dist/src/setup/flows/model-source-change.d.ts +38 -0
- package/dist/src/setup/flows/model-source-change.js +1 -0
- package/dist/src/setup/flows/model.d.ts +65 -62
- package/dist/src/setup/flows/model.js +1 -1
- package/dist/src/setup/flows/provider.d.ts +20 -0
- package/dist/src/setup/flows/provider.js +3 -3
- package/dist/src/setup/prompter.d.ts +2 -0
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/slack-connect-lifecycle.js +1 -1
- package/dist/src/setup/slackbot.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +6 -0
- package/dist/src/setup/vercel-project.js +0 -0
- package/dist/src/shared/dynamic-tool-definition.d.ts +1 -8
- package/dist/src/shared/errors.d.ts +5 -0
- package/dist/src/shared/errors.js +1 -1
- package/dist/src/shared/gateway-service-tier.d.ts +19 -0
- package/dist/src/shared/gateway-service-tier.js +1 -0
- package/dist/src/shared/model-summary.d.ts +12 -0
- package/dist/src/shared/model-summary.js +1 -0
- package/dist/src/shared/workflow-sandbox.d.ts +2 -0
- package/dist/src/shared/workflow-sandbox.js +1 -1
- package/dist/src/source-change/agent-config-ast.d.ts +54 -0
- package/dist/src/source-change/agent-config-ast.js +2 -0
- package/dist/src/source-change/agent-config-string-path.d.ts +18 -0
- package/dist/src/source-change/agent-config-string-path.js +2 -0
- package/dist/src/source-change/apply-agent-model-settings.d.ts +26 -0
- package/dist/src/source-change/apply-agent-model-settings.js +1 -0
- package/dist/src/source-change/apply-model-name.js +1 -2
- package/dist/src/source-change/static-source-change.d.ts +14 -0
- package/dist/src/source-change/static-source-change.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.d.ts +0 -6
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.d.ts +0 -2
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/concepts/execution-model-and-durability.md +1 -1
- package/docs/concepts/sessions-runs-and-streaming.md +1 -1
- package/docs/getting-started.mdx +1 -1
- package/docs/guides/auth-and-route-protection.md +1 -1
- package/docs/guides/client/overview.mdx +1 -1
- package/docs/guides/client/streaming.mdx +1 -10
- package/docs/guides/deployment/meta.json +4 -0
- package/docs/guides/deployment/overview.md +61 -0
- package/docs/guides/deployment/self-hosting.md +88 -0
- package/docs/guides/deployment/vercel.mdx +90 -0
- package/docs/guides/dev-tui.md +8 -4
- package/docs/guides/dynamic-capabilities.md +2 -0
- package/docs/guides/frontend/nextjs.mdx +1 -1
- package/docs/guides/frontend/nuxt.mdx +1 -1
- package/docs/guides/frontend/overview.mdx +2 -5
- package/docs/guides/frontend/sveltekit.mdx +1 -1
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +1 -4
- package/docs/guides/frontend/use-eve-agent-vue.mdx +1 -4
- package/docs/guides/instrumentation.md +1 -1
- package/docs/reference/cli.md +24 -2
- package/docs/tutorial/ship-it.mdx +1 -1
- package/package.json +1 -1
- package/docs/guides/deployment.md +0 -210
- /package/dist/src/cli/{dev/tui → ui}/live-region.d.ts +0 -0
- /package/dist/src/cli/{dev/tui → ui}/live-region.js +0 -0
- /package/dist/src/cli/{dev/tui → ui}/terminal-text.d.ts +0 -0
- /package/dist/src/cli/{dev/tui → ui}/terminal-text.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# eve
|
|
2
2
|
|
|
3
|
+
## 0.26.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 26504e9: The client now reconnects durable event streams from their last cursor, so long turns continue across transient connection cuts without replaying events. Stream retries are now managed internally, interrupted sessions remain resumable, and `maxReconnectAttempts` has been removed from `ClientOptions`, `EveAgentStoreInit`, and the React, Svelte, and Vue `UseEveAgentOptions` APIs.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 82fba04: Provide dynamic tools with the full auth-capable `ToolContext`, including `ctx.getToken(provider)` and `ctx.requireAuth(provider)`, across live execution and durable replay.
|
|
12
|
+
- 82fba04: Canonicalize Windows publication-lock watcher paths to avoid Node/libuv crashes when temporary directories use 8.3 short names.
|
|
13
|
+
- 51beea7: Workflow now keeps sandbox bridge capacity aligned with its configured `maxSubagents` budget, so large `Promise.all` fan-outs park and dispatch child sessions instead of failing at code mode's lower internal concurrency limit.
|
|
14
|
+
- 9a1800f: Fix `experimental_chatgpt` sending requests in an improper format that the
|
|
15
|
+
Codex backend rejected with a 400 Bad Request: system instructions are now sent
|
|
16
|
+
in the top-level `instructions` field and the unsupported `max_output_tokens`
|
|
17
|
+
parameter is dropped.
|
|
18
|
+
- 65a7823: `eve dev` now writes a private per-process diagnostic log under `.eve/logs/` capturing stderr, stdout (including sandbox and rebuild lines), tool failures, workflow errors, and eve framework log records (stored structured, with level, namespace, and JSON fields). The file is JSON Lines: every line is one JSON record with `at` and `source` fields. Long stderr output collapses in the transcript to a one-line summary pointing at the log file (the raw text stays available in the `all` log mode), and error details reference the log instead of flooding the transcript.
|
|
19
|
+
- 65a7823: `eve dev` now writes an environment dump next to each diagnostic log (`.eve/logs/dev-<instance>.dump`): one JSON document capturing eve, Node.js, and Vercel CLI versions, the Vercel CLI path, local session-store size, and running session stats (prompts, token usage, tool calls by name, subagent dispatches). `eve logs --dump` prints the dump and its JSONL log together as one parseable report.
|
|
20
|
+
- 65a7823: The dev TUI's `/model` "Change model" row now opens a value menu — Model, Reasoning effort, Service tier, Done. Reasoning and tier adjust inline with `←`/`→` (Tab acts as `→`, both wrap as a ring): a `●─◉─○` track slides over the model's supported effort levels — snapping to the closest supported level when a pick changes what the model serves — and the tier flips between `fast ↯` and `normal`; the tier row disappears when the catalog prices no priority tier for the model. Enter on Model opens the searchable catalog as model ids on a `▏` rail — the same railed list component the team and project pickers now render with. All drafted changes commit through one atomic `agent.ts` edit. The provider picker marks and describes the currently-active provider and reports an accepted key as `AI_GATEWAY_API_KEY set.`. Linking an existing project now suggests the team project named after the agent, searching for it when it is not among the recents. Command cancellations now read "dismissed". The status line drops its `·` separators and shows the model as `slug@level ↯`.
|
|
21
|
+
- 65a7823: New `eve logs` command for reading the diagnostic logs `eve dev` writes under `.eve/logs/`: `eve logs` prints the most recent log, `eve logs ls [--json]` lists them, and `eve logs <logid>` prints a specific log by id, file name, transcript path, or unambiguous prefix.
|
|
22
|
+
- 65a7823: `eve logs --events` interleaves session events (session/turn/step lifecycle, message deltas) into the diagnostic-log output, resolved at query time from the local workflow store — nothing extra is written while `eve dev` runs.
|
|
23
|
+
- b53d713: Fixed transient TUI and CLI output rendering by standardizing spinners and progress rows on the shared `LiveRegion`. Streamed command output now stays aligned beneath active spinners, while failed operations preserve their command transcript for diagnostics.
|
|
24
|
+
- 65a7823: Errors that escape a session — not just model-call failures — now pass through a semantic-error catalog: declarative, linter-style rules applied to any thrown error. Rules cover AI Gateway (auth, model-not-found, rate limits, upstream availability), model providers (missing API keys, unsupported capabilities), the durable workflow runtime (store version/access, replay divergence, corrupted event logs), sandbox backends (Docker CLI/daemon, provisioning), and system failures (port in use, disk full, network dials). Matched failures render a stable, actionable summary in the transcript with the raw error routed to the `eve dev` diagnostic log, and failure events carry a stable `semanticErrorId` for correlation.
|
|
25
|
+
|
|
3
26
|
## 0.25.3
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -176,6 +176,15 @@ const AgentInfoResultSchema = z.object({
|
|
|
176
176
|
contextWindowTokens: z.number().optional(),
|
|
177
177
|
id: z.string(),
|
|
178
178
|
providerOptions: z.unknown().optional(),
|
|
179
|
+
reasoning: z.enum([
|
|
180
|
+
"provider-default",
|
|
181
|
+
"none",
|
|
182
|
+
"minimal",
|
|
183
|
+
"low",
|
|
184
|
+
"medium",
|
|
185
|
+
"high",
|
|
186
|
+
"xhigh"
|
|
187
|
+
]).optional().catch(void 0),
|
|
179
188
|
source: source.optional(),
|
|
180
189
|
routing: modelRouting.optional(),
|
|
181
190
|
endpoint: modelEndpoint.optional()
|
|
@@ -326,6 +335,11 @@ function advanceSession(input) {
|
|
|
326
335
|
sessionId: input.sessionId,
|
|
327
336
|
streamIndex
|
|
328
337
|
};
|
|
338
|
+
if (boundaryEvent === void 0) return {
|
|
339
|
+
continuationToken: input.continuationToken ?? input.session.continuationToken,
|
|
340
|
+
sessionId: input.sessionId,
|
|
341
|
+
streamIndex
|
|
342
|
+
};
|
|
329
343
|
return createInitialSessionState();
|
|
330
344
|
}
|
|
331
345
|
function extractCompletedMessage(events) {
|
|
@@ -458,7 +472,8 @@ function formatSearch(searchParams) {
|
|
|
458
472
|
//#endregion
|
|
459
473
|
//#region src/client/open-stream.ts
|
|
460
474
|
const STREAM_OPEN_RETRY_ATTEMPTS = 12;
|
|
461
|
-
const
|
|
475
|
+
const STREAM_OPEN_RETRY_BASE_DELAY_MS = 250;
|
|
476
|
+
const STREAM_OPEN_RETRY_MAX_DELAY_MS = 5e3;
|
|
462
477
|
const STREAM_OPEN_RETRYABLE_STATUS = new Set([
|
|
463
478
|
404,
|
|
464
479
|
409,
|
|
@@ -468,32 +483,50 @@ const STREAM_OPEN_RETRYABLE_STATUS = new Set([
|
|
|
468
483
|
503,
|
|
469
484
|
504
|
|
470
485
|
]);
|
|
471
|
-
|
|
486
|
+
const STREAM_RECONNECT_BASE_DELAY_MS = 250;
|
|
487
|
+
const STREAM_RECONNECT_MAX_DELAY_MS = 4e3;
|
|
488
|
+
const STREAM_MAX_IDLE_RECONNECTS = 5;
|
|
489
|
+
async function* followStreamIterable(input) {
|
|
472
490
|
let startIndex = input.startIndex;
|
|
473
|
-
let
|
|
491
|
+
let reconnectDelayMs = STREAM_RECONNECT_BASE_DELAY_MS;
|
|
492
|
+
let idleReconnects = 0;
|
|
493
|
+
let initialConnection = true;
|
|
474
494
|
while (true) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
495
|
+
let body;
|
|
496
|
+
try {
|
|
497
|
+
body = await openStreamBody({
|
|
498
|
+
...input,
|
|
499
|
+
startIndex
|
|
500
|
+
});
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (input.signal?.aborted) return;
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
let deliveredEvent = false;
|
|
480
506
|
try {
|
|
481
507
|
for await (const event of readNdjsonStream(body)) {
|
|
482
508
|
startIndex += 1;
|
|
509
|
+
deliveredEvent = true;
|
|
510
|
+
reconnectDelayMs = STREAM_RECONNECT_BASE_DELAY_MS;
|
|
511
|
+
idleReconnects = 0;
|
|
483
512
|
yield event;
|
|
484
513
|
}
|
|
485
514
|
} catch (error) {
|
|
486
515
|
if (!isStreamDisconnectError(error)) throw error;
|
|
487
|
-
disconnected = true;
|
|
488
516
|
}
|
|
489
|
-
if (
|
|
490
|
-
|
|
517
|
+
if (input.signal?.aborted || input.startIndex < 0) return;
|
|
518
|
+
if (!deliveredEvent && !initialConnection && (idleReconnects += 1) >= STREAM_MAX_IDLE_RECONNECTS) return;
|
|
519
|
+
initialConnection = false;
|
|
520
|
+
await sleep$1(reconnectDelayMs, input.signal);
|
|
521
|
+
if (input.signal?.aborted) return;
|
|
522
|
+
reconnectDelayMs = Math.min(reconnectDelayMs * 2, STREAM_RECONNECT_MAX_DELAY_MS);
|
|
491
523
|
}
|
|
492
524
|
}
|
|
493
525
|
async function openStreamBody(input) {
|
|
494
526
|
let lastStatus;
|
|
495
527
|
let lastBody;
|
|
496
528
|
let lastHeaders;
|
|
529
|
+
let retryDelayMs = STREAM_OPEN_RETRY_BASE_DELAY_MS;
|
|
497
530
|
for (let attempt = 0; attempt < STREAM_OPEN_RETRY_ATTEMPTS; attempt += 1) {
|
|
498
531
|
const url = createClientUrl(input.host, createEveMessageStreamRoutePath(input.sessionId), input.startIndex !== 0 ? { startIndex: String(input.startIndex) } : void 0);
|
|
499
532
|
const headers = await input.resolveHeaders();
|
|
@@ -506,7 +539,8 @@ async function openStreamBody(input) {
|
|
|
506
539
|
});
|
|
507
540
|
} catch (error) {
|
|
508
541
|
if (input.signal?.aborted || !isStreamDisconnectError(error) || attempt === STREAM_OPEN_RETRY_ATTEMPTS - 1) throw error;
|
|
509
|
-
await sleep$1(
|
|
542
|
+
await sleep$1(retryDelayMs, input.signal);
|
|
543
|
+
retryDelayMs = Math.min(retryDelayMs * 2, STREAM_OPEN_RETRY_MAX_DELAY_MS);
|
|
510
544
|
continue;
|
|
511
545
|
}
|
|
512
546
|
if (response.ok) {
|
|
@@ -517,12 +551,26 @@ async function openStreamBody(input) {
|
|
|
517
551
|
lastBody = await response.text();
|
|
518
552
|
lastHeaders = response.headers;
|
|
519
553
|
if (!STREAM_OPEN_RETRYABLE_STATUS.has(response.status)) throw new ClientError(response.status, lastBody, response.headers);
|
|
520
|
-
if (attempt < STREAM_OPEN_RETRY_ATTEMPTS - 1)
|
|
554
|
+
if (attempt < STREAM_OPEN_RETRY_ATTEMPTS - 1) {
|
|
555
|
+
await sleep$1(retryDelayMs, input.signal);
|
|
556
|
+
retryDelayMs = Math.min(retryDelayMs * 2, STREAM_OPEN_RETRY_MAX_DELAY_MS);
|
|
557
|
+
}
|
|
521
558
|
}
|
|
522
559
|
throw new ClientError(lastStatus ?? 0, lastBody ?? "Failed to open message stream.", lastHeaders);
|
|
523
560
|
}
|
|
524
|
-
async function sleep$1(ms) {
|
|
525
|
-
|
|
561
|
+
async function sleep$1(ms, signal) {
|
|
562
|
+
if (signal?.aborted) return;
|
|
563
|
+
await new Promise((resolve) => {
|
|
564
|
+
const onAbort = () => {
|
|
565
|
+
clearTimeout(timer);
|
|
566
|
+
resolve();
|
|
567
|
+
};
|
|
568
|
+
const timer = setTimeout(() => {
|
|
569
|
+
signal?.removeEventListener("abort", onAbort);
|
|
570
|
+
resolve();
|
|
571
|
+
}, ms);
|
|
572
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
573
|
+
});
|
|
526
574
|
}
|
|
527
575
|
|
|
528
576
|
//#endregion
|
|
@@ -682,28 +730,17 @@ var ClientSession = class {
|
|
|
682
730
|
async *#createEventStream(sessionId, continuationToken, initialState, input) {
|
|
683
731
|
const events = [];
|
|
684
732
|
try {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
foundBoundary = true;
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
} catch (error) {
|
|
701
|
-
if (!isStreamDisconnectError(error)) throw error;
|
|
702
|
-
}
|
|
703
|
-
if (foundBoundary) break;
|
|
704
|
-
if (input.signal?.aborted) break;
|
|
705
|
-
if (remainingReconnectAttempts <= 0) break;
|
|
706
|
-
remainingReconnectAttempts -= 1;
|
|
733
|
+
for await (const event of followStreamIterable({
|
|
734
|
+
host: this.#context.host,
|
|
735
|
+
resolveHeaders: () => this.#context.resolveHeaders(input.headers),
|
|
736
|
+
redirect: this.#context.redirect,
|
|
737
|
+
sessionId,
|
|
738
|
+
signal: input.signal,
|
|
739
|
+
startIndex: initialState.sessionId === sessionId ? initialState.streamIndex : 0
|
|
740
|
+
})) {
|
|
741
|
+
events.push(event);
|
|
742
|
+
yield event;
|
|
743
|
+
if (isCurrentTurnBoundaryEvent(event)) break;
|
|
707
744
|
}
|
|
708
745
|
} finally {
|
|
709
746
|
this.#state = advanceSession({
|
|
@@ -715,24 +752,13 @@ var ClientSession = class {
|
|
|
715
752
|
});
|
|
716
753
|
}
|
|
717
754
|
}
|
|
718
|
-
async #openStreamBody(sessionId, startIndex, signal, headers) {
|
|
719
|
-
return await openStreamBody({
|
|
720
|
-
host: this.#context.host,
|
|
721
|
-
resolveHeaders: () => this.#context.resolveHeaders(headers),
|
|
722
|
-
redirect: this.#context.redirect,
|
|
723
|
-
sessionId,
|
|
724
|
-
signal,
|
|
725
|
-
startIndex
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
755
|
async *#streamAndAdvance(sessionId, options) {
|
|
729
756
|
const initialState = this.#state;
|
|
730
757
|
const streamIndex = options?.startIndex ?? initialState.streamIndex;
|
|
731
758
|
const events = [];
|
|
732
759
|
try {
|
|
733
|
-
for await (const event of
|
|
760
|
+
for await (const event of followStreamIterable({
|
|
734
761
|
host: this.#context.host,
|
|
735
|
-
maxReconnectAttempts: this.#context.maxReconnectAttempts,
|
|
736
762
|
resolveHeaders: () => this.#context.resolveHeaders(),
|
|
737
763
|
redirect: this.#context.redirect,
|
|
738
764
|
sessionId,
|
|
@@ -817,14 +843,12 @@ var Client = class {
|
|
|
817
843
|
#auth;
|
|
818
844
|
#headers;
|
|
819
845
|
#host;
|
|
820
|
-
#maxReconnectAttempts;
|
|
821
846
|
#preserveCompletedSessions;
|
|
822
847
|
#redirect;
|
|
823
848
|
constructor(options) {
|
|
824
849
|
this.#host = options.host;
|
|
825
850
|
this.#auth = options.auth;
|
|
826
851
|
this.#headers = options.headers;
|
|
827
|
-
this.#maxReconnectAttempts = options.maxReconnectAttempts ?? 3;
|
|
828
852
|
this.#preserveCompletedSessions = options.preserveCompletedSessions ?? false;
|
|
829
853
|
this.#redirect = options.redirect;
|
|
830
854
|
}
|
|
@@ -875,7 +899,6 @@ var Client = class {
|
|
|
875
899
|
else resolved = createInitialSessionState();
|
|
876
900
|
return new ClientSession({
|
|
877
901
|
host: this.#host,
|
|
878
|
-
maxReconnectAttempts: this.#maxReconnectAttempts,
|
|
879
902
|
preserveCompletedSessions: this.#preserveCompletedSessions,
|
|
880
903
|
redirect: this.#redirect,
|
|
881
904
|
resolveHeaders: (perRequest) => this.#resolveHeaders(perRequest)
|
|
@@ -951,8 +974,7 @@ var EveAgentStore = class {
|
|
|
951
974
|
this.#createSession = init.session ? void 0 : () => new Client({
|
|
952
975
|
auth: init.auth,
|
|
953
976
|
headers: init.headers,
|
|
954
|
-
host: init.host ?? ""
|
|
955
|
-
maxReconnectAttempts: init.maxReconnectAttempts
|
|
977
|
+
host: init.host ?? ""
|
|
956
978
|
}).session(init.initialSession);
|
|
957
979
|
this.#events = [...init.initialEvents ?? []];
|
|
958
980
|
this.#projectionEvents = [...this.#events];
|
|
@@ -1672,7 +1694,6 @@ function useEveAgent(options = {}) {
|
|
|
1672
1694
|
}),
|
|
1673
1695
|
initialEvents: options.initialEvents,
|
|
1674
1696
|
initialSession: options.initialSession,
|
|
1675
|
-
maxReconnectAttempts: options.maxReconnectAttempts,
|
|
1676
1697
|
optimistic: options.optimistic,
|
|
1677
1698
|
reducer,
|
|
1678
1699
|
session: options.session
|
|
@@ -176,6 +176,15 @@ const AgentInfoResultSchema = z.object({
|
|
|
176
176
|
contextWindowTokens: z.number().optional(),
|
|
177
177
|
id: z.string(),
|
|
178
178
|
providerOptions: z.unknown().optional(),
|
|
179
|
+
reasoning: z.enum([
|
|
180
|
+
"provider-default",
|
|
181
|
+
"none",
|
|
182
|
+
"minimal",
|
|
183
|
+
"low",
|
|
184
|
+
"medium",
|
|
185
|
+
"high",
|
|
186
|
+
"xhigh"
|
|
187
|
+
]).optional().catch(void 0),
|
|
179
188
|
source: source.optional(),
|
|
180
189
|
routing: modelRouting.optional(),
|
|
181
190
|
endpoint: modelEndpoint.optional()
|
|
@@ -326,6 +335,11 @@ function advanceSession(input) {
|
|
|
326
335
|
sessionId: input.sessionId,
|
|
327
336
|
streamIndex
|
|
328
337
|
};
|
|
338
|
+
if (boundaryEvent === void 0) return {
|
|
339
|
+
continuationToken: input.continuationToken ?? input.session.continuationToken,
|
|
340
|
+
sessionId: input.sessionId,
|
|
341
|
+
streamIndex
|
|
342
|
+
};
|
|
329
343
|
return createInitialSessionState();
|
|
330
344
|
}
|
|
331
345
|
function extractCompletedMessage(events) {
|
|
@@ -458,7 +472,8 @@ function formatSearch(searchParams) {
|
|
|
458
472
|
//#endregion
|
|
459
473
|
//#region src/client/open-stream.ts
|
|
460
474
|
const STREAM_OPEN_RETRY_ATTEMPTS = 12;
|
|
461
|
-
const
|
|
475
|
+
const STREAM_OPEN_RETRY_BASE_DELAY_MS = 250;
|
|
476
|
+
const STREAM_OPEN_RETRY_MAX_DELAY_MS = 5e3;
|
|
462
477
|
const STREAM_OPEN_RETRYABLE_STATUS = new Set([
|
|
463
478
|
404,
|
|
464
479
|
409,
|
|
@@ -468,32 +483,50 @@ const STREAM_OPEN_RETRYABLE_STATUS = new Set([
|
|
|
468
483
|
503,
|
|
469
484
|
504
|
|
470
485
|
]);
|
|
471
|
-
|
|
486
|
+
const STREAM_RECONNECT_BASE_DELAY_MS = 250;
|
|
487
|
+
const STREAM_RECONNECT_MAX_DELAY_MS = 4e3;
|
|
488
|
+
const STREAM_MAX_IDLE_RECONNECTS = 5;
|
|
489
|
+
async function* followStreamIterable(input) {
|
|
472
490
|
let startIndex = input.startIndex;
|
|
473
|
-
let
|
|
491
|
+
let reconnectDelayMs = STREAM_RECONNECT_BASE_DELAY_MS;
|
|
492
|
+
let idleReconnects = 0;
|
|
493
|
+
let initialConnection = true;
|
|
474
494
|
while (true) {
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
495
|
+
let body;
|
|
496
|
+
try {
|
|
497
|
+
body = await openStreamBody({
|
|
498
|
+
...input,
|
|
499
|
+
startIndex
|
|
500
|
+
});
|
|
501
|
+
} catch (error) {
|
|
502
|
+
if (input.signal?.aborted) return;
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
let deliveredEvent = false;
|
|
480
506
|
try {
|
|
481
507
|
for await (const event of readNdjsonStream(body)) {
|
|
482
508
|
startIndex += 1;
|
|
509
|
+
deliveredEvent = true;
|
|
510
|
+
reconnectDelayMs = STREAM_RECONNECT_BASE_DELAY_MS;
|
|
511
|
+
idleReconnects = 0;
|
|
483
512
|
yield event;
|
|
484
513
|
}
|
|
485
514
|
} catch (error) {
|
|
486
515
|
if (!isStreamDisconnectError(error)) throw error;
|
|
487
|
-
disconnected = true;
|
|
488
516
|
}
|
|
489
|
-
if (
|
|
490
|
-
|
|
517
|
+
if (input.signal?.aborted || input.startIndex < 0) return;
|
|
518
|
+
if (!deliveredEvent && !initialConnection && (idleReconnects += 1) >= STREAM_MAX_IDLE_RECONNECTS) return;
|
|
519
|
+
initialConnection = false;
|
|
520
|
+
await sleep$1(reconnectDelayMs, input.signal);
|
|
521
|
+
if (input.signal?.aborted) return;
|
|
522
|
+
reconnectDelayMs = Math.min(reconnectDelayMs * 2, STREAM_RECONNECT_MAX_DELAY_MS);
|
|
491
523
|
}
|
|
492
524
|
}
|
|
493
525
|
async function openStreamBody(input) {
|
|
494
526
|
let lastStatus;
|
|
495
527
|
let lastBody;
|
|
496
528
|
let lastHeaders;
|
|
529
|
+
let retryDelayMs = STREAM_OPEN_RETRY_BASE_DELAY_MS;
|
|
497
530
|
for (let attempt = 0; attempt < STREAM_OPEN_RETRY_ATTEMPTS; attempt += 1) {
|
|
498
531
|
const url = createClientUrl(input.host, createEveMessageStreamRoutePath(input.sessionId), input.startIndex !== 0 ? { startIndex: String(input.startIndex) } : void 0);
|
|
499
532
|
const headers = await input.resolveHeaders();
|
|
@@ -506,7 +539,8 @@ async function openStreamBody(input) {
|
|
|
506
539
|
});
|
|
507
540
|
} catch (error) {
|
|
508
541
|
if (input.signal?.aborted || !isStreamDisconnectError(error) || attempt === STREAM_OPEN_RETRY_ATTEMPTS - 1) throw error;
|
|
509
|
-
await sleep$1(
|
|
542
|
+
await sleep$1(retryDelayMs, input.signal);
|
|
543
|
+
retryDelayMs = Math.min(retryDelayMs * 2, STREAM_OPEN_RETRY_MAX_DELAY_MS);
|
|
510
544
|
continue;
|
|
511
545
|
}
|
|
512
546
|
if (response.ok) {
|
|
@@ -517,12 +551,26 @@ async function openStreamBody(input) {
|
|
|
517
551
|
lastBody = await response.text();
|
|
518
552
|
lastHeaders = response.headers;
|
|
519
553
|
if (!STREAM_OPEN_RETRYABLE_STATUS.has(response.status)) throw new ClientError(response.status, lastBody, response.headers);
|
|
520
|
-
if (attempt < STREAM_OPEN_RETRY_ATTEMPTS - 1)
|
|
554
|
+
if (attempt < STREAM_OPEN_RETRY_ATTEMPTS - 1) {
|
|
555
|
+
await sleep$1(retryDelayMs, input.signal);
|
|
556
|
+
retryDelayMs = Math.min(retryDelayMs * 2, STREAM_OPEN_RETRY_MAX_DELAY_MS);
|
|
557
|
+
}
|
|
521
558
|
}
|
|
522
559
|
throw new ClientError(lastStatus ?? 0, lastBody ?? "Failed to open message stream.", lastHeaders);
|
|
523
560
|
}
|
|
524
|
-
async function sleep$1(ms) {
|
|
525
|
-
|
|
561
|
+
async function sleep$1(ms, signal) {
|
|
562
|
+
if (signal?.aborted) return;
|
|
563
|
+
await new Promise((resolve) => {
|
|
564
|
+
const onAbort = () => {
|
|
565
|
+
clearTimeout(timer);
|
|
566
|
+
resolve();
|
|
567
|
+
};
|
|
568
|
+
const timer = setTimeout(() => {
|
|
569
|
+
signal?.removeEventListener("abort", onAbort);
|
|
570
|
+
resolve();
|
|
571
|
+
}, ms);
|
|
572
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
573
|
+
});
|
|
526
574
|
}
|
|
527
575
|
|
|
528
576
|
//#endregion
|
|
@@ -682,28 +730,17 @@ var ClientSession = class {
|
|
|
682
730
|
async *#createEventStream(sessionId, continuationToken, initialState, input) {
|
|
683
731
|
const events = [];
|
|
684
732
|
try {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
foundBoundary = true;
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
} catch (error) {
|
|
701
|
-
if (!isStreamDisconnectError(error)) throw error;
|
|
702
|
-
}
|
|
703
|
-
if (foundBoundary) break;
|
|
704
|
-
if (input.signal?.aborted) break;
|
|
705
|
-
if (remainingReconnectAttempts <= 0) break;
|
|
706
|
-
remainingReconnectAttempts -= 1;
|
|
733
|
+
for await (const event of followStreamIterable({
|
|
734
|
+
host: this.#context.host,
|
|
735
|
+
resolveHeaders: () => this.#context.resolveHeaders(input.headers),
|
|
736
|
+
redirect: this.#context.redirect,
|
|
737
|
+
sessionId,
|
|
738
|
+
signal: input.signal,
|
|
739
|
+
startIndex: initialState.sessionId === sessionId ? initialState.streamIndex : 0
|
|
740
|
+
})) {
|
|
741
|
+
events.push(event);
|
|
742
|
+
yield event;
|
|
743
|
+
if (isCurrentTurnBoundaryEvent(event)) break;
|
|
707
744
|
}
|
|
708
745
|
} finally {
|
|
709
746
|
this.#state = advanceSession({
|
|
@@ -715,24 +752,13 @@ var ClientSession = class {
|
|
|
715
752
|
});
|
|
716
753
|
}
|
|
717
754
|
}
|
|
718
|
-
async #openStreamBody(sessionId, startIndex, signal, headers) {
|
|
719
|
-
return await openStreamBody({
|
|
720
|
-
host: this.#context.host,
|
|
721
|
-
resolveHeaders: () => this.#context.resolveHeaders(headers),
|
|
722
|
-
redirect: this.#context.redirect,
|
|
723
|
-
sessionId,
|
|
724
|
-
signal,
|
|
725
|
-
startIndex
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
755
|
async *#streamAndAdvance(sessionId, options) {
|
|
729
756
|
const initialState = this.#state;
|
|
730
757
|
const streamIndex = options?.startIndex ?? initialState.streamIndex;
|
|
731
758
|
const events = [];
|
|
732
759
|
try {
|
|
733
|
-
for await (const event of
|
|
760
|
+
for await (const event of followStreamIterable({
|
|
734
761
|
host: this.#context.host,
|
|
735
|
-
maxReconnectAttempts: this.#context.maxReconnectAttempts,
|
|
736
762
|
resolveHeaders: () => this.#context.resolveHeaders(),
|
|
737
763
|
redirect: this.#context.redirect,
|
|
738
764
|
sessionId,
|
|
@@ -817,14 +843,12 @@ var Client = class {
|
|
|
817
843
|
#auth;
|
|
818
844
|
#headers;
|
|
819
845
|
#host;
|
|
820
|
-
#maxReconnectAttempts;
|
|
821
846
|
#preserveCompletedSessions;
|
|
822
847
|
#redirect;
|
|
823
848
|
constructor(options) {
|
|
824
849
|
this.#host = options.host;
|
|
825
850
|
this.#auth = options.auth;
|
|
826
851
|
this.#headers = options.headers;
|
|
827
|
-
this.#maxReconnectAttempts = options.maxReconnectAttempts ?? 3;
|
|
828
852
|
this.#preserveCompletedSessions = options.preserveCompletedSessions ?? false;
|
|
829
853
|
this.#redirect = options.redirect;
|
|
830
854
|
}
|
|
@@ -875,7 +899,6 @@ var Client = class {
|
|
|
875
899
|
else resolved = createInitialSessionState();
|
|
876
900
|
return new ClientSession({
|
|
877
901
|
host: this.#host,
|
|
878
|
-
maxReconnectAttempts: this.#maxReconnectAttempts,
|
|
879
902
|
preserveCompletedSessions: this.#preserveCompletedSessions,
|
|
880
903
|
redirect: this.#redirect,
|
|
881
904
|
resolveHeaders: (perRequest) => this.#resolveHeaders(perRequest)
|
|
@@ -951,8 +974,7 @@ var EveAgentStore = class {
|
|
|
951
974
|
this.#createSession = init.session ? void 0 : () => new Client({
|
|
952
975
|
auth: init.auth,
|
|
953
976
|
headers: init.headers,
|
|
954
|
-
host: init.host ?? ""
|
|
955
|
-
maxReconnectAttempts: init.maxReconnectAttempts
|
|
977
|
+
host: init.host ?? ""
|
|
956
978
|
}).session(init.initialSession);
|
|
957
979
|
this.#events = [...init.initialEvents ?? []];
|
|
958
980
|
this.#projectionEvents = [...this.#events];
|
|
@@ -1721,7 +1743,6 @@ function useEveAgent(options = {}) {
|
|
|
1721
1743
|
}),
|
|
1722
1744
|
initialEvents: options.initialEvents,
|
|
1723
1745
|
initialSession: options.initialSession,
|
|
1724
|
-
maxReconnectAttempts: options.maxReconnectAttempts,
|
|
1725
1746
|
optimistic: options.optimistic,
|
|
1726
1747
|
reducer,
|
|
1727
1748
|
session: options.session
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One session event read back from the local workflow store, shaped like a
|
|
3
|
+
* diagnostic-log line so `eve logs --events` output stays one uniform JSONL
|
|
4
|
+
* stream: `at` and `source` first, then the event identity and payload.
|
|
5
|
+
*/
|
|
6
|
+
export interface DevSessionEventLine {
|
|
7
|
+
readonly at: string;
|
|
8
|
+
readonly source: "event";
|
|
9
|
+
readonly runId: string;
|
|
10
|
+
readonly type: string;
|
|
11
|
+
readonly data?: unknown;
|
|
12
|
+
}
|
|
13
|
+
/** Time window (inclusive) of events to resolve, in wall-clock event time. */
|
|
14
|
+
export interface DevSessionEventWindow {
|
|
15
|
+
readonly from: Date;
|
|
16
|
+
readonly to: Date;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Reads session events for one diagnostic-log window from the local
|
|
20
|
+
* workflow store (`.eve/.workflow-data`), at query time — nothing is
|
|
21
|
+
* duplicated at capture time.
|
|
22
|
+
*
|
|
23
|
+
* Runs are enumerated through the vendored Workflow World API and each
|
|
24
|
+
* run's default stream is decoded through `Run.getReadable()` — the same
|
|
25
|
+
* vendored read path the dev server uses to serve session streams over
|
|
26
|
+
* HTTP — never by touching the store's private chunk encoding. The world
|
|
27
|
+
* is opened for storage reads only: `start()` is never called, so queue
|
|
28
|
+
* redelivery cannot be triggered by a CLI read, and unclosed streams
|
|
29
|
+
* (crashed processes) are drained with an idle-timeout cancel instead of
|
|
30
|
+
* waiting for chunks that will never arrive.
|
|
31
|
+
*
|
|
32
|
+
* Returns an empty list when the store does not exist. Selection is by
|
|
33
|
+
* time window: events from any `eve dev` process in the window are
|
|
34
|
+
* included, since the store does not attribute runs to processes.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readDevSessionEvents(appRoot: string, window: DevSessionEventWindow): Promise<DevSessionEventLine[]>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{access}from"node:fs/promises";import{resolveLocalWorkflowWorldDataDirectory}from"#internal/workflow/local-world-data-directory.js";async function readDevSessionEvents(n,r){let i=resolveLocalWorkflowWorldDataDirectory(n);try{await access(i)}catch{return[]}let{createWorld:a}=await import(`#compiled/@workflow/world-local/index.js`),o=await import(`#internal/workflow/runtime.js`),s=a({dataDir:i});o.setWorld(s);let c=[];for(let e of await listRunsOverlappingWindow(s,r)){let t=await drainRunStream(o,s,e.runId);c.push(...parseSessionEventLines(t,e,r))}return c.sort((e,t)=>e.at.localeCompare(t.at))}async function listRunsOverlappingWindow(e,t){let n=[],r;do{let i=await e.runs.list({resolveData:`none`,pagination:r===void 0?{limit:100}:{cursor:r,limit:100}});for(let e of i.data)e.createdAt<=t.to&&e.updatedAt>=t.from&&n.push({runId:e.runId,createdAt:e.createdAt,updatedAt:e.updatedAt});r=i.hasMore&&i.cursor!==null?i.cursor:void 0}while(r!==void 0);return n}async function drainRunStream(e,t,n){let r=``,i=new TextDecoder;try{if(!(await e.listStreams(t,n)).some(e=>e===`user`||e.endsWith(`_user`)))return``;let a=e.getRun(n).getReadable({startIndex:0}).getReader();for(;;){let e=await Promise.race([a.read(),new Promise(e=>{setTimeout(()=>e(`idle`),1e3)})]);if(e===`idle`){await a.cancel();break}if(e.done)break;r+=typeof e.value==`string`?e.value:i.decode(e.value,{stream:!0})}}catch{return``}return r}function parseSessionEventLines(e,t,n){let r=[];for(let i of e.split(`
|
|
2
|
+
`)){let e=parseSessionEvent(i);if(e===void 0)continue;let a=e.at??t.createdAt.toISOString();if(a<n.from.toISOString()||a>n.to.toISOString())continue;let o={at:a,source:`event`,runId:t.runId,type:e.type};e.data!==void 0&&(o.data=e.data),r.push(o)}return r}function parseSessionEvent(e){if(e.trim().length!==0)try{let t=JSON.parse(e);if(typeof t!=`object`||!t)return;let{type:n,data:r,meta:i}=t;if(typeof n!=`string`)return;let a=typeof i==`object`&&i&&typeof i.at==`string`?i.at:void 0,o={type:n};return a!==void 0&&(o.at=a),r!==void 0&&(o.data=r),o}catch{return}}export{readDevSessionEvents};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type DevSessionEventLine, type DevSessionEventWindow } from "./logs-events.js";
|
|
2
|
+
interface CliLogsLogger {
|
|
3
|
+
error(message: string): void;
|
|
4
|
+
log(message: string): void;
|
|
5
|
+
}
|
|
6
|
+
/** One `eve dev` diagnostic log file under `.eve/logs`. */
|
|
7
|
+
export interface DevDiagnosticLogEntry {
|
|
8
|
+
/** Stable reference: the file name without the `.log` extension. */
|
|
9
|
+
readonly id: string;
|
|
10
|
+
readonly path: string;
|
|
11
|
+
/** Process start time encoded in the file name, when parseable. */
|
|
12
|
+
readonly startedAt: Date | undefined;
|
|
13
|
+
readonly sizeBytes: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Lists `eve dev` diagnostic logs for an app root, most recent first. The
|
|
17
|
+
* sortable timestamp prefix in each file name provides the ordering; a missing
|
|
18
|
+
* log directory yields an empty list.
|
|
19
|
+
*/
|
|
20
|
+
export declare function listDevDiagnosticLogs(appRoot: string): Promise<DevDiagnosticLogEntry[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Resolves a user-supplied log reference to one entry. Accepts the full id,
|
|
23
|
+
* the file name, the transcript's `.eve/logs/...` path, or any unambiguous
|
|
24
|
+
* prefix of the id (with or without the `dev-` lead).
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveDevDiagnosticLog(logs: readonly DevDiagnosticLogEntry[], reference: string): DevDiagnosticLogEntry;
|
|
27
|
+
/** Options accepted by {@link runLogsShowCommand}. */
|
|
28
|
+
export interface LogsShowCommandOptions {
|
|
29
|
+
/** Prepend the log's environment dump (the same-instance `.dump` sibling). */
|
|
30
|
+
dump?: boolean;
|
|
31
|
+
/** Interleave session events resolved from the local workflow store. */
|
|
32
|
+
events?: boolean;
|
|
33
|
+
/** Injectable event reader and clock; defaults to the real store and `Date.now`. */
|
|
34
|
+
readEvents?: (appRoot: string, window: DevSessionEventWindow) => Promise<DevSessionEventLine[]>;
|
|
35
|
+
now?: () => Date;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* `eve logs [logid]`: prints one diagnostic log to stdout — the most recent
|
|
39
|
+
* when `logid` is omitted. The output carries nothing but records (no
|
|
40
|
+
* resolved-path banner, no progress notes on either stream), so
|
|
41
|
+
* `eve logs 2>&1 | jq` always parses; discover ids and paths with
|
|
42
|
+
* `eve logs ls`. With `--dump`, the log's environment dump (a JSON
|
|
43
|
+
* document) is prepended to the JSONL log body, forming one
|
|
44
|
+
* self-contained, parseable report. With `--events`, session events are
|
|
45
|
+
* resolved from the local workflow store at query time — never duplicated
|
|
46
|
+
* into the log at capture time — and interleaved by timestamp as
|
|
47
|
+
* `source: "event"` records.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runLogsShowCommand(logger: CliLogsLogger, appRoot: string, logId?: string, options?: LogsShowCommandOptions): Promise<void>;
|
|
50
|
+
/** Options accepted by {@link runLogsListCommand}. */
|
|
51
|
+
export interface LogsListCommandOptions {
|
|
52
|
+
/** Emit a machine-readable JSON array instead of the human listing. */
|
|
53
|
+
json?: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** Machine-readable row emitted by `eve logs ls --json`. */
|
|
56
|
+
export interface DevDiagnosticLogJson {
|
|
57
|
+
id: string;
|
|
58
|
+
path: string;
|
|
59
|
+
startedAt: string | null;
|
|
60
|
+
sizeBytes: number;
|
|
61
|
+
}
|
|
62
|
+
/** `eve logs ls`: lists diagnostic logs, most recent first. */
|
|
63
|
+
export declare function runLogsListCommand(logger: CliLogsLogger, appRoot: string, options?: LogsListCommandOptions): Promise<void>;
|
|
64
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{readDevSessionEvents}from"./logs-events.js";import{basename,join}from"node:path";import{readFile,readdir,stat}from"node:fs/promises";const LOG_DIRECTORY_SEGMENTS=[`.eve`,`logs`],LOG_DISPLAY_DIRECTORY=LOG_DIRECTORY_SEGMENTS.join(`/`),LOG_ID_PATTERN=/^dev-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.\d{3}Z)-\d+\.log$/;async function listDevDiagnosticLogs(e){let t=join(e,...LOG_DIRECTORY_SEGMENTS),r;try{r=await readdir(t)}catch(e){if(e.code===`ENOENT`)return[];throw e}let s=r.filter(e=>LOG_ID_PATTERN.test(e)).sort().reverse();return Promise.all(s.map(async e=>{let r=join(t,e);return{id:e.slice(0,-4),path:r,startedAt:parseStartedAt(e),sizeBytes:(await stat(r)).size}}))}function parseStartedAt(e){let t=LOG_ID_PATTERN.exec(e);if(t===null)return;let n=t[1].replace(/T(\d{2})-(\d{2})-(\d{2})/,`T$1:$2:$3`),r=new Date(n);return Number.isNaN(r.getTime())?void 0:r}function resolveDevDiagnosticLog(e,n){let r=basename(n.replaceAll(`\\`,`/`)),i=r.endsWith(`.log`)?r.slice(0,-4):r,a=e.find(e=>e.id===i);if(a!==void 0)return a;let o=e.filter(e=>e.id.startsWith(i)||e.id.startsWith(`dev-${i}`));if(o.length===1)return o[0];throw o.length===0?Error(`No diagnostic log matches "${n}". Run \`eve logs ls\` to see available logs.`):Error([`"${n}" matches ${o.length} diagnostic logs:`,...o.map(e=>` ${e.id}`),`Pass a longer prefix or the full id.`].join(`
|
|
2
|
+
`))}async function runLogsShowCommand(t,n,i,a={}){let o=await listDevDiagnosticLogs(n);if(o.length===0){let e=`No dev diagnostic logs found under ${LOG_DISPLAY_DIRECTORY}.`;if(i!==void 0)throw Error(e);t.log(e);return}let c=i===void 0?o[0]:resolveDevDiagnosticLog(o,i),l=await readFile(c.path,`utf8`);if(a.events===!0){let t=eventWindowForLog(o,c,a.now??(()=>new Date)),r=await(a.readEvents??readDevSessionEvents)(n,t);r.length>0&&(l=mergeLogWithEvents(l,r))}if(a.dump!==!0){t.log(l.trimEnd());return}let u=c.path.slice(0,-4)+`.dump`,d;try{d=await readFile(u,`utf8`)}catch(e){if(e.code!==`ENOENT`)throw e}if(d===void 0){t.log(l.trimEnd());return}t.log(`${d.trimEnd()}\n${l.trimEnd()}`)}function eventWindowForLog(e,t,n){let r=e.findIndex(e=>e.id===t.id),i=r>0?e[r-1].startedAt:void 0;return{from:t.startedAt??new Date(0),to:i??n()}}function mergeLogWithEvents(e,t){let n=[],r=``;for(let t of e.split(`
|
|
3
|
+
`))if(t.trim().length!==0){try{let e=JSON.parse(t).at;typeof e==`string`&&(r=e)}catch{}n.push({at:r,line:t})}let i=t.map(e=>({at:e.at,line:JSON.stringify(e)})),a=[],o=0,s=0;for(;o<n.length||s<i.length;){let e=n[o],t=i[s];t===void 0||e!==void 0&&e.at<=t.at?(a.push(e.line),o+=1):(a.push(t.line),s+=1)}return`${a.join(`
|
|
4
|
+
`)}\n`}async function runLogsListCommand(e,t,n={}){let r=await listDevDiagnosticLogs(t);if(n.json){let t=r.map(e=>({id:e.id,path:e.path,startedAt:e.startedAt?.toISOString()??null,sizeBytes:e.sizeBytes}));e.log(JSON.stringify(t,null,2));return}if(r.length===0){e.log(`No dev diagnostic logs found under ${LOG_DISPLAY_DIRECTORY}.`);return}for(let t of r){let n=t.startedAt?.toISOString()??`unknown start`;e.log(`${t.id} ${n} ${formatSize(t.sizeBytes)}`)}}function formatSize(e){if(e<1024)return`${e} B`;let t=e/1024;return t<1024?`${t.toFixed(1)} KiB`:`${(t/1024).toFixed(1)} MiB`}export{listDevDiagnosticLogs,resolveDevDiagnosticLog,runLogsListCommand,runLogsShowCommand};
|