@sapiom/harness 0.1.5 → 0.2.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 +151 -0
- package/dist/cli/args.d.ts +16 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +80 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.js +30 -66
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/consent.js +1 -1
- package/dist/cli/settings.d.ts.map +1 -1
- package/dist/cli/settings.js +33 -1
- package/dist/cli/settings.js.map +1 -1
- package/dist/core/adapters/adapter.d.ts +2 -2
- package/dist/core/adapters/claude-code.d.ts +60 -2
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +119 -32
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex.d.ts +21 -2
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +53 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/adapters/detect.d.ts +9 -0
- package/dist/core/adapters/detect.d.ts.map +1 -1
- package/dist/core/adapters/detect.js +9 -0
- package/dist/core/adapters/detect.js.map +1 -1
- package/dist/core/api-key-provider.d.ts +79 -0
- package/dist/core/api-key-provider.d.ts.map +1 -0
- package/dist/core/api-key-provider.js +91 -0
- package/dist/core/api-key-provider.js.map +1 -0
- package/dist/core/canvas-body.d.ts +28 -28
- package/dist/core/canvas-body.d.ts.map +1 -1
- package/dist/core/canvas-body.js +117 -55
- package/dist/core/canvas-body.js.map +1 -1
- package/dist/core/canvas-derive.d.ts +43 -0
- package/dist/core/canvas-derive.d.ts.map +1 -0
- package/dist/core/canvas-derive.js +95 -0
- package/dist/core/canvas-derive.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +52 -127
- package/dist/core/canvas-enrichment.d.ts.map +1 -1
- package/dist/core/canvas-enrichment.js +17 -178
- package/dist/core/canvas-enrichment.js.map +1 -1
- package/dist/core/canvas-graph.d.ts +40 -1
- package/dist/core/canvas-graph.d.ts.map +1 -1
- package/dist/core/canvas-graph.js +71 -9
- package/dist/core/canvas-graph.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +26 -8
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +132 -24
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-manifest-check.d.ts.map +1 -1
- package/dist/core/canvas-manifest-check.js +15 -2
- package/dist/core/canvas-manifest-check.js.map +1 -1
- package/dist/core/canvas-render.d.ts +8 -15
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +29 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/canvas-run-state.d.ts +50 -5
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +176 -11
- package/dist/core/canvas-run-state.js.map +1 -1
- package/dist/core/canvas-svg.d.ts +9 -4
- package/dist/core/canvas-svg.d.ts.map +1 -1
- package/dist/core/canvas-svg.js +84 -13
- package/dist/core/canvas-svg.js.map +1 -1
- package/dist/core/canvas-template.d.ts +9 -10
- package/dist/core/canvas-template.d.ts.map +1 -1
- package/dist/core/canvas-template.js +57 -20
- package/dist/core/canvas-template.js.map +1 -1
- package/dist/core/canvas-watcher.d.ts +22 -1
- package/dist/core/canvas-watcher.d.ts.map +1 -1
- package/dist/core/canvas-watcher.js +111 -30
- package/dist/core/canvas-watcher.js.map +1 -1
- package/dist/core/collector/normalizer.d.ts +8 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -1
- package/dist/core/collector/normalizer.js +8 -0
- package/dist/core/collector/normalizer.js.map +1 -1
- package/dist/core/collector/store.d.ts +75 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +334 -2
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/definition-slug-resolver.d.ts +13 -0
- package/dist/core/definition-slug-resolver.d.ts.map +1 -1
- package/dist/core/definition-slug-resolver.js +29 -0
- package/dist/core/definition-slug-resolver.js.map +1 -1
- package/dist/core/errors.d.ts +10 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +11 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/example-seed.d.ts +8 -0
- package/dist/core/example-seed.d.ts.map +1 -1
- package/dist/core/example-seed.js +47 -10
- package/dist/core/example-seed.js.map +1 -1
- package/dist/core/inject/system-prompt.d.ts +8 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -1
- package/dist/core/inject/system-prompt.js +3 -1
- package/dist/core/inject/system-prompt.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +5 -6
- package/dist/core/macros.js.map +1 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +1 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/record-archive.d.ts +187 -0
- package/dist/core/record-archive.d.ts.map +1 -0
- package/dist/core/record-archive.js +465 -0
- package/dist/core/record-archive.js.map +1 -0
- package/dist/core/rehydration.d.ts +72 -0
- package/dist/core/rehydration.d.ts.map +1 -0
- package/dist/core/rehydration.js +72 -0
- package/dist/core/rehydration.js.map +1 -0
- package/dist/core/render-local-run.d.ts +82 -0
- package/dist/core/render-local-run.d.ts.map +1 -0
- package/dist/core/render-local-run.js +105 -0
- package/dist/core/render-local-run.js.map +1 -0
- package/dist/core/render-log-slice.d.ts +30 -0
- package/dist/core/render-log-slice.d.ts.map +1 -0
- package/dist/core/render-log-slice.js +49 -0
- package/dist/core/render-log-slice.js.map +1 -0
- package/dist/core/render-run-state.d.ts.map +1 -1
- package/dist/core/render-run-state.js +30 -49
- package/dist/core/render-run-state.js.map +1 -1
- package/dist/core/resume-brief.d.ts +130 -0
- package/dist/core/resume-brief.d.ts.map +1 -0
- package/dist/core/resume-brief.js +404 -0
- package/dist/core/resume-brief.js.map +1 -0
- package/dist/core/rolling-summary.d.ts +130 -0
- package/dist/core/rolling-summary.d.ts.map +1 -0
- package/dist/core/rolling-summary.js +227 -0
- package/dist/core/rolling-summary.js.map +1 -0
- package/dist/core/run-local-bootstrap.d.ts +93 -0
- package/dist/core/run-local-bootstrap.d.ts.map +1 -0
- package/dist/core/run-local-bootstrap.js +155 -0
- package/dist/core/run-local-bootstrap.js.map +1 -0
- package/dist/core/run-state.d.ts +16 -1
- package/dist/core/run-state.d.ts.map +1 -1
- package/dist/core/run-state.js +75 -25
- package/dist/core/run-state.js.map +1 -1
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +56 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-record.d.ts +165 -0
- package/dist/core/session-record.d.ts.map +1 -0
- package/dist/core/session-record.js +470 -0
- package/dist/core/session-record.js.map +1 -0
- package/dist/core/spawn-target.d.ts +12 -0
- package/dist/core/spawn-target.d.ts.map +1 -0
- package/dist/core/spawn-target.js +187 -0
- package/dist/core/spawn-target.js.map +1 -0
- package/dist/core/stub-feedback.d.ts +52 -0
- package/dist/core/stub-feedback.d.ts.map +1 -0
- package/dist/core/stub-feedback.js +33 -0
- package/dist/core/stub-feedback.js.map +1 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +9 -1
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/template-catalog.d.ts +48 -0
- package/dist/core/template-catalog.d.ts.map +1 -0
- package/dist/core/template-catalog.js +338 -0
- package/dist/core/template-catalog.js.map +1 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +2 -2
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +4 -3
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/default.d.ts.map +1 -1
- package/dist/profiles/default.js +9 -14
- package/dist/profiles/default.js.map +1 -1
- package/dist/server/actions.d.ts +139 -0
- package/dist/server/actions.d.ts.map +1 -0
- package/dist/server/actions.js +430 -0
- package/dist/server/actions.js.map +1 -0
- package/dist/server/auth-routes.d.ts +92 -0
- package/dist/server/auth-routes.d.ts.map +1 -0
- package/dist/server/auth-routes.js +151 -0
- package/dist/server/auth-routes.js.map +1 -0
- package/dist/server/canvas.d.ts.map +1 -1
- package/dist/server/canvas.js +7 -7
- package/dist/server/canvas.js.map +1 -1
- package/dist/server/fs.d.ts.map +1 -1
- package/dist/server/fs.js +17 -1
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +11 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +1 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +4 -6
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +18 -6
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +185 -50
- package/dist/server/rest.js.map +1 -1
- package/dist/server/runs.d.ts +16 -15
- package/dist/server/runs.d.ts.map +1 -1
- package/dist/server/runs.js +15 -80
- package/dist/server/runs.js.map +1 -1
- package/dist/server/static.d.ts +15 -1
- package/dist/server/static.d.ts.map +1 -1
- package/dist/server/static.js +54 -4
- package/dist/server/static.js.map +1 -1
- package/dist/server/templates.d.ts +24 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/templates.js +54 -0
- package/dist/server/templates.js.map +1 -0
- package/dist/shared/types.d.ts +558 -66
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +19 -11
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-DC65cskq.js +446 -0
- package/dist/web/assets/index-xtD-3FFa.css +32 -0
- package/dist/web/canvas/sess-boot/index.html +305 -0
- package/dist/web/index.html +4 -9
- package/package.json +8 -4
- package/dist/core/canvas-enrich.d.ts +0 -115
- package/dist/core/canvas-enrich.d.ts.map +0 -1
- package/dist/core/canvas-enrich.js +0 -186
- package/dist/core/canvas-enrich.js.map +0 -1
- package/dist/core/run-spend.d.ts +0 -55
- package/dist/core/run-spend.d.ts.map +0 -1
- package/dist/core/run-spend.js +0 -109
- package/dist/core/run-spend.js.map +0 -1
- package/dist/core/run-transactions.d.ts +0 -60
- package/dist/core/run-transactions.d.ts.map +0 -1
- package/dist/core/run-transactions.js +0 -129
- package/dist/core/run-transactions.js.map +0 -1
- package/dist/profiles/canvas-guidelines.d.ts +0 -20
- package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
- package/dist/profiles/canvas-guidelines.js +0 -48
- package/dist/profiles/canvas-guidelines.js.map +0 -1
- package/dist/server/skills.d.ts +0 -51
- package/dist/server/skills.d.ts.map +0 -1
- package/dist/server/skills.js +0 -312
- package/dist/server/skills.js.map +0 -1
- package/dist/web/assets/index-DM84J83Y.js +0 -234
- package/dist/web/assets/index-DemtWW4L.css +0 -32
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuilds a past session's transcript from OUR OWN recorded events, not from
|
|
3
|
+
* any vendor's transcript file — which is what makes it work identically for
|
|
4
|
+
* claude-code and codex (both normalize into the same AnalyticsEvent stream;
|
|
5
|
+
* see core/collector/normalizer.ts and core/collector/codex-tailer.ts) and
|
|
6
|
+
* makes it survive the vendor deleting, rotating, or never writing its own
|
|
7
|
+
* history.
|
|
8
|
+
*
|
|
9
|
+
* The fold: `prompt.submitted` opens a turn, `tool.call`s attach to the open
|
|
10
|
+
* turn, `turn.completed` closes it with assistantText / model / usage. Events
|
|
11
|
+
* that arrive with no open turn still get a turn of their own (with a null
|
|
12
|
+
* prompt) rather than being dropped — a record whose recording started
|
|
13
|
+
* mid-turn is a real case, and silently discarding those events would show a
|
|
14
|
+
* session as emptier than it was.
|
|
15
|
+
*
|
|
16
|
+
* ORDERING — the one non-obvious rule. `AnalyticsEvent.seq` is NOT a
|
|
17
|
+
* session-lifetime ordering key: it comes from an in-memory per-boot counter
|
|
18
|
+
* (core/collector/seq.ts), so it restarts at 1 on every harness boot and every
|
|
19
|
+
* fresh pty. A real resumed session reads seq 1, 2 then 1, 1, 1. Sorting by
|
|
20
|
+
* `seq` alone would interleave a resume's events into the middle of the first
|
|
21
|
+
* run. Sort by `(ts, seq)`: wall-clock time orders the epochs, and `seq` only
|
|
22
|
+
* breaks ties inside one of them. A restart is a new epoch, never loss.
|
|
23
|
+
*
|
|
24
|
+
* HONESTY — what this can never recover, surfaced as `limitations` on the
|
|
25
|
+
* record so the UI can say it out loud:
|
|
26
|
+
* - `tool.call` stores a size-capped `toolResponseSummary`; large tool
|
|
27
|
+
* outputs are gone from our log.
|
|
28
|
+
* - `turn.completed` carries only the Stop hook's LAST assistant message
|
|
29
|
+
* (see the header of core/collector/transcript.ts for why), so assistant
|
|
30
|
+
* narration *between* tool calls is absent. The tool-call stream fills the
|
|
31
|
+
* chronology, not the prose.
|
|
32
|
+
* - Codex's rollout has no equivalent of that field at all, so its turns
|
|
33
|
+
* carry tool calls and prompts but no assistant text.
|
|
34
|
+
*
|
|
35
|
+
* RETENTION — why a record can outlive the events it was folded from. The
|
|
36
|
+
* ndjson is capped at 50 MB / 30 days (collector/store-retention.ts), so a
|
|
37
|
+
* record built only from it would silently disappear a month later. At session
|
|
38
|
+
* end a compacted copy is written to `~/.sapiom/harness/records/` and the
|
|
39
|
+
* reader falls back to it once the log no longer covers the conversation
|
|
40
|
+
* (core/record-archive.ts; the rule is spelled out on `read` below).
|
|
41
|
+
*/
|
|
42
|
+
import * as os from "node:os";
|
|
43
|
+
import * as path from "node:path";
|
|
44
|
+
import { projectDirsFor } from "./adapters/claude-code.js";
|
|
45
|
+
import { PAYLOAD_TRUNCATION_MARKER } from "./collector/normalizer.js";
|
|
46
|
+
import { readLastAssistantTurn } from "./collector/transcript.js";
|
|
47
|
+
function stringOrNull(value) {
|
|
48
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
49
|
+
}
|
|
50
|
+
function numberOrNull(value) {
|
|
51
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
52
|
+
}
|
|
53
|
+
function readUsage(value) {
|
|
54
|
+
if (typeof value !== "object" || value === null)
|
|
55
|
+
return null;
|
|
56
|
+
const usage = value;
|
|
57
|
+
const inputTokens = numberOrNull(usage.inputTokens);
|
|
58
|
+
const outputTokens = numberOrNull(usage.outputTokens);
|
|
59
|
+
if (inputTokens === null && outputTokens === null)
|
|
60
|
+
return null;
|
|
61
|
+
return { inputTokens, outputTokens };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Order events for folding: `ts` first, `seq` only as a tiebreak within the
|
|
65
|
+
* same millisecond. See the module header for why `seq` alone is wrong.
|
|
66
|
+
* Array.prototype.sort is stable, so events matching on both keep file order.
|
|
67
|
+
*/
|
|
68
|
+
export function sortEventsForFold(events) {
|
|
69
|
+
return [...events].sort((a, b) => {
|
|
70
|
+
if (a.ts !== b.ts)
|
|
71
|
+
return a.ts < b.ts ? -1 : 1;
|
|
72
|
+
const seqA = typeof a.seq === "number" ? a.seq : 0;
|
|
73
|
+
const seqB = typeof b.seq === "number" ? b.seq : 0;
|
|
74
|
+
return seqA - seqB;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Fold an event stream into an ordered {@link SessionRecord}. Pure and
|
|
79
|
+
* synchronous: hand it the events for one session (or for a set of sessions
|
|
80
|
+
* that share an agent session — a resumed conversation) and it returns the
|
|
81
|
+
* transcript. Events for other sessions are tolerated and folded in; the
|
|
82
|
+
* caller is responsible for filtering, which `EventStore.read` does by index.
|
|
83
|
+
*/
|
|
84
|
+
export function foldSessionRecord(events, options = {}) {
|
|
85
|
+
const ordered = sortEventsForFold(events);
|
|
86
|
+
const turns = [];
|
|
87
|
+
let open = null;
|
|
88
|
+
let startedAt = null;
|
|
89
|
+
let endedAt = null;
|
|
90
|
+
let cwd = null;
|
|
91
|
+
let harness = options.harness ?? null;
|
|
92
|
+
let agentSessionId = null;
|
|
93
|
+
const seenSessionIds = [];
|
|
94
|
+
/** Move the open turn into `turns`, closed by `completion` or incomplete. */
|
|
95
|
+
function close(completion) {
|
|
96
|
+
if (!open)
|
|
97
|
+
return;
|
|
98
|
+
const payload = completion?.payload ?? {};
|
|
99
|
+
turns.push({
|
|
100
|
+
index: turns.length + 1,
|
|
101
|
+
prompt: open.prompt,
|
|
102
|
+
promptAt: open.promptAt,
|
|
103
|
+
toolCalls: open.toolCalls,
|
|
104
|
+
assistantText: stringOrNull(payload.assistantText),
|
|
105
|
+
model: stringOrNull(payload.model),
|
|
106
|
+
usage: readUsage(payload.usage),
|
|
107
|
+
completedAt: completion?.ts ?? null,
|
|
108
|
+
incomplete: completion === null,
|
|
109
|
+
});
|
|
110
|
+
open = null;
|
|
111
|
+
}
|
|
112
|
+
for (const event of ordered) {
|
|
113
|
+
if (!seenSessionIds.includes(event.harnessSessionId))
|
|
114
|
+
seenSessionIds.push(event.harnessSessionId);
|
|
115
|
+
if (startedAt === null)
|
|
116
|
+
startedAt = event.ts;
|
|
117
|
+
if (harness === null && typeof event.harness === "string")
|
|
118
|
+
harness = event.harness;
|
|
119
|
+
if (agentSessionId === null)
|
|
120
|
+
agentSessionId = stringOrNull(event.agentSessionId);
|
|
121
|
+
const payload = event.payload ?? {};
|
|
122
|
+
switch (event.type) {
|
|
123
|
+
case "session.start":
|
|
124
|
+
if (cwd === null)
|
|
125
|
+
cwd = stringOrNull(payload.cwd);
|
|
126
|
+
break;
|
|
127
|
+
case "prompt.submitted":
|
|
128
|
+
// A prompt arriving while a turn is open means that turn never
|
|
129
|
+
// completed (killed mid-turn, or the user queued another prompt).
|
|
130
|
+
// Keep it, marked incomplete — dropping it would lose real tool calls.
|
|
131
|
+
close(null);
|
|
132
|
+
open = {
|
|
133
|
+
prompt: typeof payload.prompt === "string" ? payload.prompt : "",
|
|
134
|
+
promptAt: event.ts,
|
|
135
|
+
toolCalls: [],
|
|
136
|
+
};
|
|
137
|
+
break;
|
|
138
|
+
case "tool.call": {
|
|
139
|
+
// No enclosing turn: the recording started mid-turn (a resume attaches
|
|
140
|
+
// its hooks after the prompt was already submitted). Open an anonymous
|
|
141
|
+
// turn so the calls are in the chronology, honestly promptless.
|
|
142
|
+
if (!open)
|
|
143
|
+
open = { prompt: null, promptAt: null, toolCalls: [] };
|
|
144
|
+
const responseSummary = stringOrNull(payload.toolResponseSummary);
|
|
145
|
+
open.toolCalls.push({
|
|
146
|
+
name: stringOrNull(payload.toolName),
|
|
147
|
+
input: stringOrNull(payload.toolInput),
|
|
148
|
+
responseSummary,
|
|
149
|
+
responseTruncated: responseSummary !== null && PAYLOAD_TRUNCATION_MARKER.test(responseSummary),
|
|
150
|
+
at: event.ts,
|
|
151
|
+
});
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case "turn.completed":
|
|
155
|
+
// A completion with nothing open is an agent-initiated turn (or one
|
|
156
|
+
// whose prompt predates our recording) — give it a promptless turn.
|
|
157
|
+
if (!open)
|
|
158
|
+
open = { prompt: null, promptAt: null, toolCalls: [] };
|
|
159
|
+
close(event);
|
|
160
|
+
break;
|
|
161
|
+
case "session.end":
|
|
162
|
+
// Never closes the open turn: a session that ended mid-turn HAS an
|
|
163
|
+
// incomplete trailing turn, and that's what the record should say.
|
|
164
|
+
endedAt = event.ts;
|
|
165
|
+
break;
|
|
166
|
+
default:
|
|
167
|
+
// Every other type (UI-interaction analytics: session.switched,
|
|
168
|
+
// macro.invoked, …) is not part of the conversation. Counted in
|
|
169
|
+
// eventCount, deliberately not rendered as a turn.
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
close(null);
|
|
174
|
+
const merged = options.mergedSessionIds ? [...options.mergedSessionIds] : seenSessionIds;
|
|
175
|
+
return {
|
|
176
|
+
harnessSessionId: options.harnessSessionId ?? merged[0] ?? "",
|
|
177
|
+
mergedSessionIds: merged,
|
|
178
|
+
agentSessionId,
|
|
179
|
+
harness: harness ?? "claude-code",
|
|
180
|
+
cwd,
|
|
181
|
+
startedAt,
|
|
182
|
+
endedAt,
|
|
183
|
+
turns,
|
|
184
|
+
turnCount: turns.filter((turn) => turn.prompt !== null).length,
|
|
185
|
+
eventCount: ordered.length,
|
|
186
|
+
reconstructed: true,
|
|
187
|
+
// Folded from the live log, not read from the archive. The archive is the
|
|
188
|
+
// only thing that sets this (core/record-archive.ts).
|
|
189
|
+
archivedAt: null,
|
|
190
|
+
limitations: computeLimitations(turns),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Derive the record's honest gaps from the turns themselves.
|
|
195
|
+
*
|
|
196
|
+
* A pure function of the turn list, and called again by the reader after any
|
|
197
|
+
* enrichment — deliberately, because gaps can APPEAR as well as disappear when
|
|
198
|
+
* a turn is filled in. Giving a turn that has tool calls its assistant text
|
|
199
|
+
* back closes `missing-assistant-text` and simultaneously opens
|
|
200
|
+
* `assistant-narration-gap` (only the turn's *final* message was ever
|
|
201
|
+
* recorded). Patching individual codes after the fact got that wrong and
|
|
202
|
+
* under-reported a real gap.
|
|
203
|
+
*/
|
|
204
|
+
function computeLimitations(turns) {
|
|
205
|
+
const limitations = [];
|
|
206
|
+
if (turns.some((turn) => turn.toolCalls.some((call) => call.responseTruncated))) {
|
|
207
|
+
limitations.push("truncated-tool-output");
|
|
208
|
+
}
|
|
209
|
+
if (turns.some((turn) => turn.toolCalls.length > 0 && turn.assistantText !== null)) {
|
|
210
|
+
limitations.push("assistant-narration-gap");
|
|
211
|
+
}
|
|
212
|
+
if (turns.some((turn) => turn.completedAt !== null && turn.assistantText === null)) {
|
|
213
|
+
limitations.push("missing-assistant-text");
|
|
214
|
+
}
|
|
215
|
+
if (turns.length > 0 && turns[turns.length - 1].incomplete) {
|
|
216
|
+
limitations.push("incomplete-final-turn");
|
|
217
|
+
}
|
|
218
|
+
return limitations;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Resolve a requested id to every harnessSessionId whose events belong in its
|
|
222
|
+
* record. A conversation can span several harness sessions (resuming the same
|
|
223
|
+
* agent session id), and the record should be the conversation, not one of its
|
|
224
|
+
* segments. One hop through the agent-session alias map — deliberately not a
|
|
225
|
+
* transitive closure, which could chain unrelated sessions together.
|
|
226
|
+
*/
|
|
227
|
+
function resolveSessionIds(index, id) {
|
|
228
|
+
const ids = [];
|
|
229
|
+
const add = (candidate) => {
|
|
230
|
+
if (!ids.includes(candidate) && index.bySession.has(candidate))
|
|
231
|
+
ids.push(candidate);
|
|
232
|
+
};
|
|
233
|
+
const direct = index.bySession.get(id);
|
|
234
|
+
if (direct) {
|
|
235
|
+
add(id);
|
|
236
|
+
for (const agentSessionId of direct.agentSessionIds) {
|
|
237
|
+
for (const sibling of index.byAgentSession.get(agentSessionId) ?? [])
|
|
238
|
+
add(sibling);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
// Not a harnessSessionId we know — try it as an agent session id.
|
|
243
|
+
for (const sibling of index.byAgentSession.get(id) ?? [])
|
|
244
|
+
add(sibling);
|
|
245
|
+
}
|
|
246
|
+
// Earliest first, so the record's primary id is where the conversation began.
|
|
247
|
+
return ids.sort((a, b) => {
|
|
248
|
+
const tsA = index.bySession.get(a)?.firstTs ?? "";
|
|
249
|
+
const tsB = index.bySession.get(b)?.firstTs ?? "";
|
|
250
|
+
if (tsA !== tsB)
|
|
251
|
+
return tsA < tsB ? -1 : 1;
|
|
252
|
+
return a < b ? -1 : 1;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Reader over the local event store, and — when one is wired in — over the
|
|
257
|
+
* durable record archive that outlives it (core/record-archive.ts). `read`
|
|
258
|
+
* touches only the byte spans the index attributes to the session, so opening a
|
|
259
|
+
* record never rescans the (up to 50 MB) ndjson; see `read`'s own comment for
|
|
260
|
+
* how it chooses between the two sources.
|
|
261
|
+
*
|
|
262
|
+
* MEMORY CEILING — stated, because a global `(ts, seq)` order can't be produced
|
|
263
|
+
* from a stream: `read` holds the whole session's events at once. That is ONE
|
|
264
|
+
* copy, not two — `sortEventsForFold` copies the array of references, and the
|
|
265
|
+
* turns reference the same payload strings the events do. Measured against a
|
|
266
|
+
* 50 MB log owned by a single session at real event density (~4.3 KB/event):
|
|
267
|
+
* 12k events, ~50 MB of record content against ~52 MB on disk (see
|
|
268
|
+
* session-record.perf.test.ts, which asserts that ratio so a regression that
|
|
269
|
+
* duplicates the data or buffers the raw file gets caught).
|
|
270
|
+
*
|
|
271
|
+
* So the ceiling is "one session's share of a file capped at 50 MB", which for
|
|
272
|
+
* the pathological single-session case is ~50 MB of transient heap in a local
|
|
273
|
+
* server. That is deliberate and bounded rather than unbounded; if a future
|
|
274
|
+
* caller needs a tighter bound (H3's rehydration reading only recent context,
|
|
275
|
+
* say), the fix is a `limit`/most-recent-N on the wire, not a change of order.
|
|
276
|
+
*/
|
|
277
|
+
export function createSessionRecordReader(store, options = {}) {
|
|
278
|
+
const archive = options.archive;
|
|
279
|
+
const reader = {
|
|
280
|
+
/**
|
|
281
|
+
* SOURCE SELECTION — the one rule worth reading twice.
|
|
282
|
+
*
|
|
283
|
+
* The ticket asked for "prefer the archive when it exists, fall back to
|
|
284
|
+
* scanning events". Taken literally that is wrong in two directions, so
|
|
285
|
+
* this prefers whichever source still holds the WHOLE conversation, which
|
|
286
|
+
* is the archive exactly when the log no longer does:
|
|
287
|
+
*
|
|
288
|
+
* - Preferring the archive for a session that ended a minute ago serves a
|
|
289
|
+
* compacted excerpt (clipped tool payloads) when the full events are
|
|
290
|
+
* right there. Scanning them is not the expensive thing it would have
|
|
291
|
+
* been before H2's byte-offset index — a record open reads only that
|
|
292
|
+
* session's spans.
|
|
293
|
+
* - A conversation that gets RESUMED keeps writing into the log after its
|
|
294
|
+
* first archive. "Always prefer the archive" would freeze its record at
|
|
295
|
+
* the first exit and quietly hide every later turn.
|
|
296
|
+
*
|
|
297
|
+
* The log holds the whole conversation when it still holds the beginning of
|
|
298
|
+
* it: the sweep truncates oldest-first (store-retention.ts), so coverage is
|
|
299
|
+
* always a suffix — an intact first event means nothing in between was
|
|
300
|
+
* dropped. Events newer than the archive mean the conversation continued,
|
|
301
|
+
* which makes the log the fuller source regardless.
|
|
302
|
+
*
|
|
303
|
+
* Neither source → null. A record that was never recorded and one that was
|
|
304
|
+
* swept both answer 404 today; what changed is that far fewer sessions
|
|
305
|
+
* reach that state.
|
|
306
|
+
*/
|
|
307
|
+
async read(id) {
|
|
308
|
+
const archived = archive ? await archive.read(id).catch(() => null) : null;
|
|
309
|
+
if (!archived)
|
|
310
|
+
return reader.readFromEvents(id);
|
|
311
|
+
const index = await store.index();
|
|
312
|
+
const sessionIds = resolveSessionIds(index, id);
|
|
313
|
+
const entries = sessionIds.map((sessionId) => index.bySession.get(sessionId)).filter(isPresent);
|
|
314
|
+
const firstTs = earliest(entries.map((entry) => entry.firstTs));
|
|
315
|
+
const lastTs = latest(entries.map((entry) => entry.lastTs));
|
|
316
|
+
const logHoldsTheBeginning = firstTs !== null && (archived.startedAt === null || firstTs <= archived.startedAt);
|
|
317
|
+
const logHasNewerEvents = lastTs !== null && archived.archivedAt !== null && lastTs > archived.archivedAt;
|
|
318
|
+
if (!logHoldsTheBeginning && !logHasNewerEvents)
|
|
319
|
+
return archived;
|
|
320
|
+
return (await reader.readFromEvents(id)) ?? archived;
|
|
321
|
+
},
|
|
322
|
+
async readFromEvents(id) {
|
|
323
|
+
const index = await store.index();
|
|
324
|
+
const sessionIds = resolveSessionIds(index, id);
|
|
325
|
+
if (sessionIds.length === 0)
|
|
326
|
+
return null;
|
|
327
|
+
const events = [];
|
|
328
|
+
for await (const event of store.read({ harnessSessionId: sessionIds }))
|
|
329
|
+
events.push(event);
|
|
330
|
+
if (events.length === 0)
|
|
331
|
+
return null;
|
|
332
|
+
const record = foldSessionRecord(events, {
|
|
333
|
+
harnessSessionId: sessionIds[0],
|
|
334
|
+
mergedSessionIds: sessionIds,
|
|
335
|
+
});
|
|
336
|
+
if (!options.enrichFinalTurn)
|
|
337
|
+
return record;
|
|
338
|
+
const final = record.turns[record.turns.length - 1];
|
|
339
|
+
// Only ever fills gaps in the last COMPLETED turn — that is the one the
|
|
340
|
+
// vendor's tail-read can speak to (see readLastAssistantTurn). An
|
|
341
|
+
// incomplete trailing turn is skipped on purpose: the transcript's last
|
|
342
|
+
// assistant message then belongs to some earlier turn, and attaching it
|
|
343
|
+
// here would be a fabrication dressed as an enhancement. Nothing our own
|
|
344
|
+
// events recorded is ever overwritten.
|
|
345
|
+
if (!final || final.completedAt === null)
|
|
346
|
+
return record;
|
|
347
|
+
if (final.assistantText !== null && final.model !== null && final.usage !== null)
|
|
348
|
+
return record;
|
|
349
|
+
const enrichment = await options.enrichFinalTurn(record).catch(() => null);
|
|
350
|
+
if (!enrichment)
|
|
351
|
+
return record;
|
|
352
|
+
const enriched = {
|
|
353
|
+
...final,
|
|
354
|
+
assistantText: final.assistantText ?? enrichment.assistantText,
|
|
355
|
+
model: final.model ?? enrichment.model,
|
|
356
|
+
usage: final.usage ?? enrichment.usage,
|
|
357
|
+
};
|
|
358
|
+
const turns = [...record.turns.slice(0, -1), enriched];
|
|
359
|
+
// Recomputed, not patched: filling a turn can open a gap as well as close
|
|
360
|
+
// one — see computeLimitations.
|
|
361
|
+
return { ...record, turns, limitations: computeLimitations(turns) };
|
|
362
|
+
},
|
|
363
|
+
async turnCounts() {
|
|
364
|
+
const index = await store.index();
|
|
365
|
+
const counts = new Map();
|
|
366
|
+
// Every key — harness-session and agent-session alike — counts the whole
|
|
367
|
+
// CONVERSATION that `read(id)` would fold for it, not the one segment the
|
|
368
|
+
// index happens to file it under. A conversation resumed under a second
|
|
369
|
+
// harness session must not report two different turn counts depending on
|
|
370
|
+
// which id a history row was keyed by; a row's count has to match the
|
|
371
|
+
// record it links to.
|
|
372
|
+
const totalFor = (id) => {
|
|
373
|
+
let total = 0;
|
|
374
|
+
for (const sessionId of resolveSessionIds(index, id)) {
|
|
375
|
+
total += index.bySession.get(sessionId)?.turnCount ?? 0;
|
|
376
|
+
}
|
|
377
|
+
return total;
|
|
378
|
+
};
|
|
379
|
+
for (const harnessSessionId of index.bySession.keys()) {
|
|
380
|
+
counts.set(harnessSessionId, totalFor(harnessSessionId));
|
|
381
|
+
}
|
|
382
|
+
for (const agentSessionId of index.byAgentSession.keys()) {
|
|
383
|
+
counts.set(agentSessionId, totalFor(agentSessionId));
|
|
384
|
+
}
|
|
385
|
+
// Then the archive, for every key the log can no longer speak for. `max`
|
|
386
|
+
// rather than "fill the gaps": a swept conversation's live count has
|
|
387
|
+
// decayed to a fraction of what happened (or to nothing at all), and a
|
|
388
|
+
// resumed one's live count is the larger, more current number. Taking the
|
|
389
|
+
// greater of the two is right in both directions.
|
|
390
|
+
if (archive) {
|
|
391
|
+
const archived = await archive.list().catch((err) => {
|
|
392
|
+
console.error("[harness] archived record counts failed:", err);
|
|
393
|
+
return [];
|
|
394
|
+
});
|
|
395
|
+
for (const entry of archived) {
|
|
396
|
+
for (const key of entry.keys) {
|
|
397
|
+
counts.set(key, Math.max(counts.get(key) ?? 0, entry.turnCount));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return counts;
|
|
402
|
+
},
|
|
403
|
+
async conversationIds() {
|
|
404
|
+
const index = await store.index();
|
|
405
|
+
const primaries = new Map();
|
|
406
|
+
for (const harnessSessionId of index.bySession.keys()) {
|
|
407
|
+
// resolveSessionIds returns the conversation earliest-first, so its
|
|
408
|
+
// head is the primary id every segment agrees on — which is what
|
|
409
|
+
// dedupes a resumed conversation down to one entry here.
|
|
410
|
+
const [primary] = resolveSessionIds(index, harnessSessionId);
|
|
411
|
+
if (primary === undefined || primaries.has(primary))
|
|
412
|
+
continue;
|
|
413
|
+
primaries.set(primary, latest(resolveSessionIds(index, primary).map((id) => index.bySession.get(id)?.lastTs ?? null)));
|
|
414
|
+
}
|
|
415
|
+
return [...primaries.entries()]
|
|
416
|
+
.sort(([idA, tsA], [idB, tsB]) => {
|
|
417
|
+
if (tsA !== tsB)
|
|
418
|
+
return (tsB ?? "") < (tsA ?? "") ? -1 : 1;
|
|
419
|
+
return idA < idB ? -1 : 1;
|
|
420
|
+
})
|
|
421
|
+
.map(([id]) => id);
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
return reader;
|
|
425
|
+
}
|
|
426
|
+
function isPresent(value) {
|
|
427
|
+
return value !== undefined;
|
|
428
|
+
}
|
|
429
|
+
/** The smallest / largest non-null ISO timestamp, or null when there is none.
|
|
430
|
+
* ISO-8601 in UTC sorts lexicographically, which is why these compare strings
|
|
431
|
+
* rather than parsing dates. */
|
|
432
|
+
function earliest(timestamps) {
|
|
433
|
+
return timestamps.reduce((best, ts) => (ts === null ? best : best === null || ts < best ? ts : best), null);
|
|
434
|
+
}
|
|
435
|
+
function latest(timestamps) {
|
|
436
|
+
return timestamps.reduce((best, ts) => (ts === null ? best : best === null || ts > best ? ts : best), null);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Fills the LAST turn's model / usage / assistant text from Claude Code's own
|
|
440
|
+
* transcript, when that file happens to still be on disk — a pure enhancement
|
|
441
|
+
* over what our events recorded, wired in via
|
|
442
|
+
* {@link createSessionRecordReader}'s `enrichFinalTurn`.
|
|
443
|
+
*
|
|
444
|
+
* Everything about it is best-effort by design: wrong harness, no cwd, no
|
|
445
|
+
* agent session id, transcript deleted or rotated → null, and the record
|
|
446
|
+
* renders from our events alone. Reuses `readLastAssistantTurn`, so it reads
|
|
447
|
+
* only the tail of a transcript that can be hundreds of MB.
|
|
448
|
+
*/
|
|
449
|
+
export function createClaudeTranscriptEnricher(options = {}) {
|
|
450
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
451
|
+
return async (record) => {
|
|
452
|
+
if (record.harness !== "claude-code")
|
|
453
|
+
return null;
|
|
454
|
+
if (!record.cwd || !record.agentSessionId)
|
|
455
|
+
return null;
|
|
456
|
+
// projectDirsFor (shared with the adapter's canResume / listPastSessions)
|
|
457
|
+
// handles the trap here: Claude Code stores transcripts under the REALPATH
|
|
458
|
+
// of the project, so a session opened in /tmp/proj lives under
|
|
459
|
+
// `-private-tmp-proj` and a hand-built path silently finds nothing. It
|
|
460
|
+
// returns the resolved candidate first and the raw one as a fallback, so
|
|
461
|
+
// this tries both rather than betting on either.
|
|
462
|
+
for (const projectDir of await projectDirsFor(homeDir, record.cwd)) {
|
|
463
|
+
const turn = await readLastAssistantTurn(path.join(projectDir, `${record.agentSessionId}.jsonl`));
|
|
464
|
+
if (turn)
|
|
465
|
+
return turn;
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
//# sourceMappingURL=session-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-record.js","sourceRoot":"","sources":["../../src/core/session-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAUlC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAGlE,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5E,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC7D,MAAM,KAAK,GAAG,KAA0D,CAAC;IACzE,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtD,IAAI,WAAW,KAAK,IAAI,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAiC;IACjE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC/B,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAmBD;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAiC,EACjC,UAAuB,EAAE;IAEzB,MAAM,OAAO,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,IAAI,IAAI,GAAoB,IAAI,CAAC;IACjC,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,GAAG,GAAkB,IAAI,CAAC;IAC9B,IAAI,OAAO,GAAuB,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;IAC1D,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,6EAA6E;IAC7E,SAAS,KAAK,CAAC,UAAiC;QAC9C,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,OAAO,GAAG,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC;YACT,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,aAAa,EAAE,YAAY,CAAC,OAAO,CAAC,aAAa,CAAC;YAClD,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC;YAC/B,WAAW,EAAE,UAAU,EAAE,EAAE,IAAI,IAAI;YACnC,UAAU,EAAE,UAAU,KAAK,IAAI;SAChC,CAAC,CAAC;QACH,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAAE,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAClG,IAAI,SAAS,KAAK,IAAI;YAAE,SAAS,GAAG,KAAK,CAAC,EAAE,CAAC;QAC7C,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QACnF,IAAI,cAAc,KAAK,IAAI;YAAE,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;QAEpC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,eAAe;gBAClB,IAAI,GAAG,KAAK,IAAI;oBAAE,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAClD,MAAM;YAER,KAAK,kBAAkB;gBACrB,+DAA+D;gBAC/D,kEAAkE;gBAClE,uEAAuE;gBACvE,KAAK,CAAC,IAAI,CAAC,CAAC;gBACZ,IAAI,GAAG;oBACL,MAAM,EAAE,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;oBAChE,QAAQ,EAAE,KAAK,CAAC,EAAE;oBAClB,SAAS,EAAE,EAAE;iBACd,CAAC;gBACF,MAAM;YAER,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,uEAAuE;gBACvE,uEAAuE;gBACvE,gEAAgE;gBAChE,IAAI,CAAC,IAAI;oBAAE,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;gBAClE,MAAM,eAAe,GAAG,YAAY,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;gBAClE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAClB,IAAI,EAAE,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC;oBACpC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,SAAS,CAAC;oBACtC,eAAe;oBACf,iBAAiB,EAAE,eAAe,KAAK,IAAI,IAAI,yBAAyB,CAAC,IAAI,CAAC,eAAe,CAAC;oBAC9F,EAAE,EAAE,KAAK,CAAC,EAAE;iBACb,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;YAED,KAAK,gBAAgB;gBACnB,oEAAoE;gBACpE,oEAAoE;gBACpE,IAAI,CAAC,IAAI;oBAAE,IAAI,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;gBAClE,KAAK,CAAC,KAAK,CAAC,CAAC;gBACb,MAAM;YAER,KAAK,aAAa;gBAChB,mEAAmE;gBACnE,mEAAmE;gBACnE,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC;gBACnB,MAAM;YAER;gBACE,gEAAgE;gBAChE,gEAAgE;gBAChE,mDAAmD;gBACnD,MAAM;QACV,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,CAAC;IAEZ,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;IACzF,OAAO;QACL,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE;QAC7D,gBAAgB,EAAE,MAAM;QACxB,cAAc;QACd,OAAO,EAAE,OAAO,IAAI,aAAa;QACjC,GAAG;QACH,SAAS;QACT,OAAO;QACP,KAAK;QACL,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM;QAC9D,UAAU,EAAE,OAAO,CAAC,MAAM;QAC1B,aAAa,EAAE,IAAI;QACnB,0EAA0E;QAC1E,sDAAsD;QACtD,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC;KACvC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAAC,KAAmC;IAC7D,MAAM,WAAW,GAA8B,EAAE,CAAC;IAClD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC;QAChF,WAAW,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC5C,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,EAAE,CAAC;QACnF,WAAW,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC9C,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,CAAC,EAAE,CAAC;QACnF,WAAW,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC7C,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;QAC3D,WAAW,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AA4DD;;;;;;GAMG;AACH,SAAS,iBAAiB,CAAC,KAAiB,EAAE,EAAU;IACtD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,CAAC,SAAiB,EAAQ,EAAE;QACtC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtF,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC;QACX,GAAG,CAAC,EAAE,CAAC,CAAC;QACR,KAAK,MAAM,cAAc,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YACpD,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE;gBAAE,GAAG,CAAC,OAAO,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,kEAAkE;QAClE,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACzE,CAAC;IAED,8EAA8E;IAC9E,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;QAClD,IAAI,GAAG,KAAK,GAAG;YAAE,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAkB,EAClB,UAAmF,EAAE;IAErF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAEhC,MAAM,MAAM,GAAwB;QAClC;;;;;;;;;;;;;;;;;;;;;;;;;;WA0BG;QACH,KAAK,CAAC,IAAI,CAAC,EAAU;YACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC3E,IAAI,CAAC,QAAQ;gBAAE,OAAO,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAEhD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAChG,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAChE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;YAE5D,MAAM,oBAAoB,GACxB,OAAO,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC;YACrF,MAAM,iBAAiB,GACrB,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,KAAK,IAAI,IAAI,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC;YAClF,IAAI,CAAC,oBAAoB,IAAI,CAAC,iBAAiB;gBAAE,OAAO,QAAQ,CAAC;YACjE,OAAO,CAAC,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC;QACvD,CAAC;QAED,KAAK,CAAC,cAAc,CAAC,EAAU;YAC7B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAChD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAEzC,MAAM,MAAM,GAAqB,EAAE,CAAC;YACpC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,gBAAgB,EAAE,UAAU,EAAE,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAErC,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,EAAE;gBACvC,gBAAgB,EAAE,UAAU,CAAC,CAAC,CAAC;gBAC/B,gBAAgB,EAAE,UAAU;aAC7B,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,eAAe;gBAAE,OAAO,MAAM,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACpD,wEAAwE;YACxE,kEAAkE;YAClE,wEAAwE;YACxE,wEAAwE;YACxE,yEAAyE;YACzE,uCAAuC;YACvC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI;gBAAE,OAAO,MAAM,CAAC;YACxD,IAAI,KAAK,CAAC,aAAa,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;gBAAE,OAAO,MAAM,CAAC;YAChG,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3E,IAAI,CAAC,UAAU;gBAAE,OAAO,MAAM,CAAC;YAC/B,MAAM,QAAQ,GAAsB;gBAClC,GAAG,KAAK;gBACR,aAAa,EAAE,KAAK,CAAC,aAAa,IAAI,UAAU,CAAC,aAAa;gBAC9D,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK;gBACtC,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK;aACvC,CAAC;YACF,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YACvD,0EAA0E;YAC1E,gCAAgC;YAChC,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACtE,CAAC;QAED,KAAK,CAAC,UAAU;YACd,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;YAEzC,yEAAyE;YACzE,0EAA0E;YAC1E,wEAAwE;YACxE,yEAAyE;YACzE,sEAAsE;YACtE,sBAAsB;YACtB,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAU,EAAE;gBACtC,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,KAAK,MAAM,SAAS,IAAI,iBAAiB,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;oBACrD,KAAK,IAAI,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,IAAI,CAAC,CAAC;gBAC1D,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC,CAAC;YAEF,KAAK,MAAM,gBAAgB,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAC3D,CAAC;YACD,KAAK,MAAM,cAAc,IAAI,KAAK,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,CAAC;gBACzD,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;YACvD,CAAC;YAED,yEAAyE;YACzE,qEAAqE;YACrE,uEAAuE;YACvE,0EAA0E;YAC1E,kDAAkD;YAClD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;oBAC3D,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;oBAC/D,OAAO,EAAE,CAAC;gBACZ,CAAC,CAAC,CAAC;gBACH,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;oBAC7B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;wBAC7B,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,KAAK,CAAC,eAAe;YACnB,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAyB,CAAC;YACnD,KAAK,MAAM,gBAAgB,IAAI,KAAK,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,oEAAoE;gBACpE,iEAAiE;gBACjE,yDAAyD;gBACzD,MAAM,CAAC,OAAO,CAAC,GAAG,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;gBAC7D,IAAI,OAAO,KAAK,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;oBAAE,SAAS;gBAC9D,SAAS,CAAC,GAAG,CACX,OAAO,EACP,MAAM,CACJ,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,MAAM,IAAI,IAAI,CAAC,CACvF,CACF,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;iBAC5B,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE;gBAC/B,IAAI,GAAG,KAAK,GAAG;oBAAE,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3D,OAAO,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5B,CAAC,CAAC;iBACD,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAI,KAAoB;IACxC,OAAO,KAAK,KAAK,SAAS,CAAC;AAC7B,CAAC;AAED;;iCAEiC;AACjC,SAAS,QAAQ,CAAC,UAAsC;IACtD,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC3E,IAAI,CACL,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,UAAsC;IACpD,OAAO,UAAU,CAAC,MAAM,CACtB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC3E,IAAI,CACL,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,8BAA8B,CAC5C,UAAgC,EAAE;IAElC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC;IAChD,OAAO,KAAK,EAAE,MAAqB,EAAE,EAAE;QACrC,IAAI,MAAM,CAAC,OAAO,KAAK,aAAa;YAAE,OAAO,IAAI,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC;QACvD,0EAA0E;QAC1E,2EAA2E;QAC3E,+DAA+D;QAC/D,uEAAuE;QACvE,yEAAyE;QACzE,iDAAiD;QACjD,KAAK,MAAM,UAAU,IAAI,MAAM,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACnE,MAAM,IAAI,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,cAAc,QAAQ,CAAC,CAAC,CAAC;YAClG,IAAI,IAAI;gBAAE,OAAO,IAAI,CAAC;QACxB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface SpawnTarget {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface SpawnTargetDeps {
|
|
6
|
+
platform?: NodeJS.Platform;
|
|
7
|
+
env?: NodeJS.ProcessEnv;
|
|
8
|
+
fileExists?: (p: string) => boolean;
|
|
9
|
+
readText?: (p: string) => string;
|
|
10
|
+
}
|
|
11
|
+
export declare function resolveSpawnTarget(command: string, args: readonly string[], deps?: SpawnTargetDeps): SpawnTarget;
|
|
12
|
+
//# sourceMappingURL=spawn-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-target.d.ts","sourceRoot":"","sources":["../../src/core/spawn-target.ts"],"names":[],"mappings":"AA4CA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CAClC;AA8HD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,GAAE,eAAoB,GACzB,WAAW,CAyCb"}
|