@xemahq/kernel-contracts 0.49.3 → 0.56.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/dist/app-definition/lib/automation.d.ts.map +1 -1
- package/dist/app-definition/lib/automation.js.map +1 -1
- package/dist/biome/lib/biome-manifest.d.ts +9 -0
- package/dist/biome/lib/biome-manifest.d.ts.map +1 -1
- package/dist/biome/lib/biome-manifest.js +2 -0
- package/dist/biome/lib/biome-manifest.js.map +1 -1
- package/dist/capability/index.d.ts +2 -1
- package/dist/capability/index.d.ts.map +1 -1
- package/dist/capability/index.js +2 -1
- package/dist/capability/index.js.map +1 -1
- package/dist/capability/lib/authority-effect.d.ts +8 -0
- package/dist/capability/lib/authority-effect.d.ts.map +1 -0
- package/dist/capability/lib/authority-effect.js +17 -0
- package/dist/capability/lib/authority-effect.js.map +1 -0
- package/dist/capability/lib/capability-contribution.d.ts +4 -0
- package/dist/capability/lib/capability-contribution.d.ts.map +1 -1
- package/dist/capability/lib/capability-contribution.js +4 -0
- package/dist/capability/lib/capability-contribution.js.map +1 -1
- package/dist/capability/lib/capability-domain.d.ts +8 -0
- package/dist/capability/lib/capability-domain.d.ts.map +1 -0
- package/dist/capability/lib/capability-domain.js +24 -0
- package/dist/capability/lib/capability-domain.js.map +1 -0
- package/dist/capability/lib/meta-tool.d.ts +51 -14
- package/dist/capability/lib/meta-tool.d.ts.map +1 -1
- package/dist/capability/lib/meta-tool.js +66 -12
- package/dist/capability/lib/meta-tool.js.map +1 -1
- package/dist/capability-projection/index.d.ts +4 -0
- package/dist/capability-projection/index.d.ts.map +1 -0
- package/dist/capability-projection/index.js +20 -0
- package/dist/capability-projection/index.js.map +1 -0
- package/dist/capability-projection/lib/capability-invocation-binding.d.ts +72 -0
- package/dist/capability-projection/lib/capability-invocation-binding.d.ts.map +1 -0
- package/dist/capability-projection/lib/capability-invocation-binding.js +101 -0
- package/dist/capability-projection/lib/capability-invocation-binding.js.map +1 -0
- package/dist/capability-projection/lib/capability-sync-manifest.d.ts +8 -0
- package/dist/capability-projection/lib/capability-sync-manifest.d.ts.map +1 -0
- package/dist/capability-projection/lib/capability-sync-manifest.js +8 -0
- package/dist/capability-projection/lib/capability-sync-manifest.js.map +1 -0
- package/dist/capability-projection/lib/projected-capability.d.ts +15 -0
- package/dist/capability-projection/lib/projected-capability.d.ts.map +1 -0
- package/dist/capability-projection/lib/projected-capability.js +17 -0
- package/dist/capability-projection/lib/projected-capability.js.map +1 -0
- package/dist/connector/lib/connector-adapter-contribution.d.ts +2 -0
- package/dist/connector/lib/connector-adapter-contribution.d.ts.map +1 -1
- package/dist/connector/lib/onboarding-manifest.d.ts +2 -0
- package/dist/connector/lib/onboarding-manifest.d.ts.map +1 -1
- package/dist/connector/lib/onboarding-manifest.js +1 -0
- package/dist/connector/lib/onboarding-manifest.js.map +1 -1
- package/dist/connector/lib/provider-descriptor.d.ts +2 -0
- package/dist/connector/lib/provider-descriptor.d.ts.map +1 -1
- package/dist/contribution/lib/contribution-kind.d.ts +1 -4
- package/dist/contribution/lib/contribution-kind.d.ts.map +1 -1
- package/dist/contribution/lib/contribution-kind.js +1 -4
- package/dist/contribution/lib/contribution-kind.js.map +1 -1
- package/dist/distribution/index.d.ts +1 -0
- package/dist/distribution/index.d.ts.map +1 -1
- package/dist/distribution/index.js +1 -0
- package/dist/distribution/index.js.map +1 -1
- package/dist/distribution/lib/distribution-lock.d.ts +6 -0
- package/dist/distribution/lib/distribution-lock.d.ts.map +1 -1
- package/dist/distribution/lib/distribution-lock.js +9 -1
- package/dist/distribution/lib/distribution-lock.js.map +1 -1
- package/dist/distribution/lib/first-party-capability-domains.d.ts +15 -0
- package/dist/distribution/lib/first-party-capability-domains.d.ts.map +1 -0
- package/dist/distribution/lib/first-party-capability-domains.js +52 -0
- package/dist/distribution/lib/first-party-capability-domains.js.map +1 -0
- package/dist/object/lib/xema-object-ref.d.ts +0 -5
- package/dist/object/lib/xema-object-ref.d.ts.map +1 -1
- package/dist/object/lib/xema-object-ref.js +12 -62
- package/dist/object/lib/xema-object-ref.js.map +1 -1
- package/dist/output-surface-inspect/index.d.ts +1 -0
- package/dist/output-surface-inspect/index.d.ts.map +1 -1
- package/dist/output-surface-inspect/index.js +1 -0
- package/dist/output-surface-inspect/index.js.map +1 -1
- package/dist/output-surface-inspect/lib/buffers.d.ts +52 -0
- package/dist/output-surface-inspect/lib/buffers.d.ts.map +1 -0
- package/dist/output-surface-inspect/lib/buffers.js +132 -0
- package/dist/output-surface-inspect/lib/buffers.js.map +1 -0
- package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts +6 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.d.ts.map +1 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.js +12 -1
- package/dist/output-surface-inspect/lib/output-surface-inspect.js.map +1 -1
- package/dist/output-surface-inspect/lib/step-schema.d.ts +2 -1
- package/dist/output-surface-inspect/lib/step-schema.d.ts.map +1 -1
- package/dist/output-surface-inspect/lib/step-schema.js +9 -2
- package/dist/output-surface-inspect/lib/step-schema.js.map +1 -1
- package/dist/output-surface-inspect/runtime/index.d.ts +1 -0
- package/dist/output-surface-inspect/runtime/index.d.ts.map +1 -1
- package/dist/output-surface-inspect/runtime/index.js +1 -0
- package/dist/output-surface-inspect/runtime/index.js.map +1 -1
- package/dist/search/index.d.ts +1 -0
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -0
- package/dist/search/index.js.map +1 -1
- package/dist/search/lib/route-template.d.ts +31 -0
- package/dist/search/lib/route-template.d.ts.map +1 -0
- package/dist/search/lib/route-template.js +142 -0
- package/dist/search/lib/route-template.js.map +1 -0
- package/dist/search/lib/search-contribution.d.ts +2 -0
- package/dist/search/lib/search-contribution.d.ts.map +1 -1
- package/dist/search/lib/search-contribution.js +34 -1
- package/dist/search/lib/search-contribution.js.map +1 -1
- package/dist/search-source/lib/indexable-document.d.ts +22 -0
- package/dist/search-source/lib/indexable-document.d.ts.map +1 -1
- package/dist/search-source/lib/indexable-document.js +10 -1
- package/dist/search-source/lib/indexable-document.js.map +1 -1
- package/dist/search-source/lib/search-index-event.d.ts +10 -0
- package/dist/search-source/lib/search-index-event.d.ts.map +1 -1
- package/dist/search-source/lib/search-ref.d.ts.map +1 -1
- package/dist/search-source/lib/search-ref.js +11 -2
- package/dist/search-source/lib/search-ref.js.map +1 -1
- package/dist/search-source/lib/search-replay.d.ts +10 -0
- package/dist/search-source/lib/search-replay.d.ts.map +1 -1
- package/dist/service-registry/lib/service-descriptor.d.ts +1 -0
- package/dist/service-registry/lib/service-descriptor.d.ts.map +1 -1
- package/dist/space/lib/space-ref-parser.d.ts +6 -4
- package/dist/space/lib/space-ref-parser.d.ts.map +1 -1
- package/dist/space/lib/space-ref-parser.js +90 -126
- package/dist/space/lib/space-ref-parser.js.map +1 -1
- package/dist/space/lib/space-traversal.d.ts.map +1 -1
- package/dist/space/lib/space-traversal.js +9 -13
- package/dist/space/lib/space-traversal.js.map +1 -1
- package/dist/space/lib/space.d.ts +9 -0
- package/dist/space/lib/space.d.ts.map +1 -1
- package/dist/space/lib/space.js +59 -29
- package/dist/space/lib/space.js.map +1 -1
- package/dist/subject/lib/subject.d.ts +1 -0
- package/dist/subject/lib/subject.d.ts.map +1 -1
- package/dist/subject/lib/subject.js +1 -0
- package/dist/subject/lib/subject.js.map +1 -1
- package/dist/surface/index.d.ts +4 -0
- package/dist/surface/index.d.ts.map +1 -0
- package/dist/surface/index.js +20 -0
- package/dist/surface/index.js.map +1 -0
- package/dist/surface/lib/surface-contribution.d.ts +24 -0
- package/dist/surface/lib/surface-contribution.d.ts.map +1 -0
- package/dist/surface/lib/surface-contribution.js +23 -0
- package/dist/surface/lib/surface-contribution.js.map +1 -0
- package/dist/surface/lib/surface-kind.d.ts +23 -0
- package/dist/surface/lib/surface-kind.d.ts.map +1 -0
- package/dist/surface/lib/surface-kind.js +27 -0
- package/dist/surface/lib/surface-kind.js.map +1 -0
- package/dist/surface/lib/vista-surface.d.ts +11 -0
- package/dist/surface/lib/vista-surface.d.ts.map +1 -0
- package/dist/surface/lib/vista-surface.js +13 -0
- package/dist/surface/lib/vista-surface.js.map +1 -0
- package/dist/widget/lib/chat-widget-envelope.d.ts.map +1 -1
- package/dist/widget/lib/chat-widget-envelope.js.map +1 -1
- package/dist/workflow/lib/enums.d.ts.map +1 -1
- package/dist/workflow/lib/enums.js.map +1 -1
- package/package.json +1 -1
- package/src/app-definition/lib/automation.ts +3 -2
- package/src/biome/lib/biome-manifest.ts +41 -1
- package/src/capability/index.ts +2 -1
- package/src/capability/lib/authority-effect.ts +88 -0
- package/src/capability/lib/capability-contribution.ts +46 -0
- package/src/capability/lib/capability-domain.ts +51 -0
- package/src/capability/lib/capability-grant.ts +1 -1
- package/src/capability/lib/meta-tool.ts +172 -39
- package/src/capability-projection/index.ts +3 -0
- package/src/capability-projection/lib/capability-invocation-binding.ts +223 -0
- package/src/capability-projection/lib/capability-sync-manifest.ts +52 -0
- package/src/capability-projection/lib/projected-capability.ts +63 -0
- package/src/connector/lib/onboarding-manifest.ts +16 -0
- package/src/contribution/lib/contribution-kind.ts +30 -29
- package/src/distribution/index.ts +1 -0
- package/src/distribution/lib/distribution-lock.ts +36 -0
- package/src/distribution/lib/first-party-capability-domains.ts +166 -0
- package/src/object/lib/xema-object-ref.ts +27 -82
- package/src/output-surface-inspect/index.ts +2 -0
- package/src/output-surface-inspect/lib/buffers.ts +252 -0
- package/src/output-surface-inspect/lib/output-surface-inspect.ts +65 -6
- package/src/output-surface-inspect/lib/step-schema.ts +36 -3
- package/src/output-surface-inspect/runtime/index.ts +1 -0
- package/src/search/index.ts +1 -0
- package/src/search/lib/route-template.ts +381 -0
- package/src/search/lib/search-contribution.ts +84 -11
- package/src/search-source/lib/indexable-document.ts +44 -0
- package/src/search-source/lib/search-ref.ts +22 -9
- package/src/service-registry/lib/service-descriptor.ts +16 -0
- package/src/space/lib/skill-mirror-path.ts +1 -1
- package/src/space/lib/space-ref-parser.ts +190 -165
- package/src/space/lib/space-traversal.ts +34 -17
- package/src/space/lib/space.ts +148 -35
- package/src/subject/lib/subject.ts +16 -0
- package/src/surface/index.ts +3 -0
- package/src/surface/lib/surface-contribution.ts +101 -0
- package/src/surface/lib/surface-kind.ts +65 -0
- package/src/surface/lib/vista-surface.ts +44 -0
- package/src/widget/lib/chat-widget-envelope.ts +6 -2
- package/src/workflow/lib/enums.ts +6 -7
- package/dist/capability/lib/first-party-capability-domains.d.ts +0 -30
- package/dist/capability/lib/first-party-capability-domains.d.ts.map +0 -1
- package/dist/capability/lib/first-party-capability-domains.js +0 -36
- package/dist/capability/lib/first-party-capability-domains.js.map +0 -1
- package/src/capability/lib/first-party-capability-domains.ts +0 -77
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// buffers.ts — bounded console / network ring buffers.
|
|
3
|
+
//
|
|
4
|
+
// SHARED, not per-target. Both inspect executors observe continuously and let
|
|
5
|
+
// the agent pull windows on demand:
|
|
6
|
+
// • the in-page bridge (`output-surface-inspector/bridge`) patches console
|
|
7
|
+
// and fetch/XHR in the user's tab;
|
|
8
|
+
// • the governed headless executor subscribes to the equivalent
|
|
9
|
+
// browser-level events.
|
|
10
|
+
// A `console` / `network` step must mean exactly the same thing on both, so
|
|
11
|
+
// the ring eviction, the consecutive-duplicate collapse, the filtering and the
|
|
12
|
+
// `{entries, collected, returned, dropped, truncated, cursor}` envelope live
|
|
13
|
+
// here once instead of being reimplemented per target.
|
|
14
|
+
//
|
|
15
|
+
// Deliberately zod-free and DOM-free so the browser bridge can bundle it.
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
clampInspectReadLimit,
|
|
20
|
+
INSPECT_BUFFER_MAX_BYTES,
|
|
21
|
+
INSPECT_BUFFER_MAX_ENTRIES,
|
|
22
|
+
INSPECT_CONSOLE_LEVEL_VALUES,
|
|
23
|
+
INSPECT_ENTRY_MAX_BYTES,
|
|
24
|
+
InspectConsoleLevel,
|
|
25
|
+
} from './output-surface-inspect';
|
|
26
|
+
import type {
|
|
27
|
+
InspectConsoleEntry,
|
|
28
|
+
InspectNetworkEntry,
|
|
29
|
+
InspectReadResult,
|
|
30
|
+
OutputSurfaceRuntimeErrorItem,
|
|
31
|
+
} from './output-surface-inspect';
|
|
32
|
+
|
|
33
|
+
function clip(text: string, max: number): string {
|
|
34
|
+
if (text.length <= max) {
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
37
|
+
return `${text.slice(0, max)}…[+${text.length - max} chars]`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Mutable entries — `cursor` is a monotonic id assigned on insert; `count`
|
|
41
|
+
// and `lastAt` mutate when consecutive identical console lines collapse.
|
|
42
|
+
interface ConsoleRecord extends Omit<InspectConsoleEntry, 'count' | 'lastAt'> {
|
|
43
|
+
cursor: number;
|
|
44
|
+
count: number;
|
|
45
|
+
lastAt: number;
|
|
46
|
+
}
|
|
47
|
+
interface NetworkRecord extends InspectNetworkEntry {
|
|
48
|
+
cursor: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
abstract class RingBuffer<T extends { cursor: number }> {
|
|
52
|
+
protected entries: T[] = [];
|
|
53
|
+
protected nextCursor = 1;
|
|
54
|
+
/** Entries evicted by the ring (so reads can report `dropped`). */
|
|
55
|
+
protected evicted = 0;
|
|
56
|
+
private bytes = 0;
|
|
57
|
+
|
|
58
|
+
protected sizeOf(entry: T): number {
|
|
59
|
+
try {
|
|
60
|
+
return JSON.stringify(entry).length;
|
|
61
|
+
} catch {
|
|
62
|
+
return INSPECT_ENTRY_MAX_BYTES;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
protected append(entry: T): void {
|
|
67
|
+
entry.cursor = this.nextCursor++;
|
|
68
|
+
this.entries.push(entry);
|
|
69
|
+
this.bytes += this.sizeOf(entry);
|
|
70
|
+
while (
|
|
71
|
+
this.entries.length > INSPECT_BUFFER_MAX_ENTRIES ||
|
|
72
|
+
(this.bytes > INSPECT_BUFFER_MAX_BYTES && this.entries.length > 1)
|
|
73
|
+
) {
|
|
74
|
+
const dropped = this.entries.shift();
|
|
75
|
+
if (!dropped) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
this.bytes -= this.sizeOf(dropped);
|
|
79
|
+
this.evicted += 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Total entries ever held minus what is currently retained. */
|
|
84
|
+
get totalCollected(): number {
|
|
85
|
+
return this.entries.length + this.evicted;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Filters shared by both windowed reads. `limit` is clamped by the buffer. */
|
|
90
|
+
export interface InspectBufferReadOptions {
|
|
91
|
+
sinceMs?: number | undefined;
|
|
92
|
+
sinceCursor?: number | undefined;
|
|
93
|
+
grep?: string | undefined;
|
|
94
|
+
limit?: number | undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface InspectConsoleReadOptions extends InspectBufferReadOptions {
|
|
98
|
+
levels?: readonly InspectConsoleLevel[] | undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface InspectNetworkReadOptions extends InspectBufferReadOptions {
|
|
102
|
+
failedOnly?: boolean | undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Drop the internal `cursor` bookkeeping field. The cursor is a buffer detail —
|
|
107
|
+
* it is reported ONCE per read (as the envelope's `cursor`), never per entry.
|
|
108
|
+
*/
|
|
109
|
+
function withoutCursor<TRecord extends { cursor: number }>(
|
|
110
|
+
record: TRecord,
|
|
111
|
+
): Omit<TRecord, 'cursor'> {
|
|
112
|
+
const copy: Record<string, unknown> = { ...record };
|
|
113
|
+
delete copy.cursor;
|
|
114
|
+
return copy as Omit<TRecord, 'cursor'>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Assemble the shared read envelope from a filtered set. */
|
|
118
|
+
function envelope<TEntry, TRecord extends { cursor: number }>(
|
|
119
|
+
all: readonly TRecord[],
|
|
120
|
+
matched: readonly TRecord[],
|
|
121
|
+
limit: number,
|
|
122
|
+
collected: number,
|
|
123
|
+
evicted: number,
|
|
124
|
+
sinceCursor: number | undefined,
|
|
125
|
+
): InspectReadResult<TEntry> {
|
|
126
|
+
const window = matched.slice(-limit);
|
|
127
|
+
const maxCursor = all.reduce((m, e) => Math.max(m, e.cursor), sinceCursor ?? 0);
|
|
128
|
+
return {
|
|
129
|
+
entries: window.map((record) => withoutCursor(record) as TEntry),
|
|
130
|
+
collected,
|
|
131
|
+
returned: window.length,
|
|
132
|
+
dropped: evicted + (matched.length - window.length),
|
|
133
|
+
truncated: matched.length > window.length,
|
|
134
|
+
cursor: maxCursor,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class ConsoleBuffer extends RingBuffer<ConsoleRecord> {
|
|
139
|
+
push(input: {
|
|
140
|
+
level: InspectConsoleLevel;
|
|
141
|
+
text: string;
|
|
142
|
+
source: InspectConsoleEntry['source'];
|
|
143
|
+
}): void {
|
|
144
|
+
const text = clip(input.text, INSPECT_ENTRY_MAX_BYTES);
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
const last = this.entries[this.entries.length - 1];
|
|
147
|
+
// Collapse consecutive identical lines (level+source+text) into a count.
|
|
148
|
+
if (
|
|
149
|
+
last !== undefined &&
|
|
150
|
+
last.level === input.level &&
|
|
151
|
+
last.source === input.source &&
|
|
152
|
+
last.text === text
|
|
153
|
+
) {
|
|
154
|
+
last.count += 1;
|
|
155
|
+
last.lastAt = now;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.append({
|
|
159
|
+
cursor: 0,
|
|
160
|
+
level: input.level,
|
|
161
|
+
text,
|
|
162
|
+
source: input.source,
|
|
163
|
+
count: 1,
|
|
164
|
+
firstAt: now,
|
|
165
|
+
lastAt: now,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Bounded error summary for the passive `xema:runtime-errors` push. */
|
|
170
|
+
errorSummary(maxDistinct: number): {
|
|
171
|
+
total: number;
|
|
172
|
+
top: OutputSurfaceRuntimeErrorItem[];
|
|
173
|
+
} {
|
|
174
|
+
const errors = this.entries.filter(
|
|
175
|
+
(e) => e.level === InspectConsoleLevel.Error,
|
|
176
|
+
);
|
|
177
|
+
const total = errors.reduce((sum, e) => sum + e.count, 0);
|
|
178
|
+
const top = [...errors]
|
|
179
|
+
.sort((a, b) => b.count - a.count)
|
|
180
|
+
.slice(0, maxDistinct)
|
|
181
|
+
.map((e) => ({ text: e.text, count: e.count, source: e.source }));
|
|
182
|
+
return { total, top };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
read(opts: InspectConsoleReadOptions): InspectReadResult<InspectConsoleEntry> {
|
|
186
|
+
const cutoff = opts.sinceMs ? Date.now() - opts.sinceMs : 0;
|
|
187
|
+
const grep = opts.grep?.toLowerCase();
|
|
188
|
+
const levels =
|
|
189
|
+
opts.levels && opts.levels.length > 0
|
|
190
|
+
? opts.levels
|
|
191
|
+
: INSPECT_CONSOLE_LEVEL_VALUES;
|
|
192
|
+
const matched = this.entries.filter(
|
|
193
|
+
(e) =>
|
|
194
|
+
e.lastAt >= cutoff &&
|
|
195
|
+
(opts.sinceCursor === undefined || e.cursor > opts.sinceCursor) &&
|
|
196
|
+
levels.includes(e.level) &&
|
|
197
|
+
(!grep || e.text.toLowerCase().includes(grep)),
|
|
198
|
+
);
|
|
199
|
+
return envelope<InspectConsoleEntry, ConsoleRecord>(
|
|
200
|
+
this.entries,
|
|
201
|
+
matched,
|
|
202
|
+
clampInspectReadLimit(opts.limit),
|
|
203
|
+
this.totalCollected,
|
|
204
|
+
this.evicted,
|
|
205
|
+
opts.sinceCursor,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export class NetworkBuffer extends RingBuffer<NetworkRecord> {
|
|
211
|
+
push(input: InspectNetworkEntry): void {
|
|
212
|
+
this.append({ cursor: 0, ...input });
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Update the most recent matching in-flight request (by url+method). */
|
|
216
|
+
complete(
|
|
217
|
+
url: string,
|
|
218
|
+
method: string | undefined,
|
|
219
|
+
patch: Partial<InspectNetworkEntry>,
|
|
220
|
+
): void {
|
|
221
|
+
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
222
|
+
const e = this.entries[i];
|
|
223
|
+
if (e === undefined) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (e.url === url && e.method === method && e.durationMs === undefined) {
|
|
227
|
+
Object.assign(e, patch);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
read(opts: InspectNetworkReadOptions): InspectReadResult<InspectNetworkEntry> {
|
|
234
|
+
const cutoff = opts.sinceMs ? Date.now() - opts.sinceMs : 0;
|
|
235
|
+
const grep = opts.grep?.toLowerCase();
|
|
236
|
+
const matched = this.entries.filter(
|
|
237
|
+
(e) =>
|
|
238
|
+
e.startedAt >= cutoff &&
|
|
239
|
+
(opts.sinceCursor === undefined || e.cursor > opts.sinceCursor) &&
|
|
240
|
+
(!grep || e.url.toLowerCase().includes(grep)) &&
|
|
241
|
+
(!opts.failedOnly || e.failed === true || (e.status ?? 0) >= 400),
|
|
242
|
+
);
|
|
243
|
+
return envelope<InspectNetworkEntry, NetworkRecord>(
|
|
244
|
+
this.entries,
|
|
245
|
+
matched,
|
|
246
|
+
clampInspectReadLimit(opts.limit),
|
|
247
|
+
this.totalCollected,
|
|
248
|
+
this.evicted,
|
|
249
|
+
opts.sinceCursor,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -21,10 +21,19 @@
|
|
|
21
21
|
// ─── Target backends ────────────────────────────────────────────────────────
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Which browser the inspect batch runs against. Closed set.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
24
|
+
* Which browser the inspect batch runs against. Closed set.
|
|
25
|
+
*
|
|
26
|
+
* • `UserTab` — the user's own live output-surface tab. The broker relays each
|
|
27
|
+
* step to the injected bridge and results return out-of-band. The tab is
|
|
28
|
+
* ATTACHED: it already shows a page, and it can never leave the project
|
|
29
|
+
* origin (doing so loses the bridge — see {@link InspectStepStatus.OffDomain}).
|
|
30
|
+
* • `Headless` — a governed headless browser the platform opens for the batch
|
|
31
|
+
* (`web-access-api`). It is SELF-OPENED: there is no pre-existing page, so
|
|
32
|
+
* the batch MUST begin with a `navigate` step carrying an absolute `url`, and
|
|
33
|
+
* an off-origin page is inspectable instead of being a dead end.
|
|
34
|
+
*
|
|
35
|
+
* The step language, the limits, the statuses and {@link InspectBatchResult}
|
|
36
|
+
* are IDENTICAL for both — only the transport differs.
|
|
28
37
|
*/
|
|
29
38
|
export enum InspectTargetKind {
|
|
30
39
|
UserTab = 'user-tab',
|
|
@@ -143,10 +152,32 @@ export interface InspectWindowedRead {
|
|
|
143
152
|
limit?: number | undefined;
|
|
144
153
|
}
|
|
145
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Go somewhere. Carries EXACTLY ONE of `path` or `url` — never both, never
|
|
157
|
+
* neither (enforced by `InspectStepSchema`, not by convention).
|
|
158
|
+
*
|
|
159
|
+
* The two are deliberately separate fields rather than one overloaded string:
|
|
160
|
+
* a target that cannot leave its origin (`InspectTargetKind.UserTab`) must be
|
|
161
|
+
* able to REFUSE an absolute navigation fail-fast, which is impossible if the
|
|
162
|
+
* caller's intent is hidden inside the syntax of a single value.
|
|
163
|
+
*/
|
|
146
164
|
export interface InspectNavigateStep {
|
|
147
165
|
kind: InspectStepKind.Navigate;
|
|
148
|
-
/**
|
|
149
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Origin-RELATIVE path, e.g. `/checkout`, resolved against the page the step
|
|
168
|
+
* runs on. Requires a page to already be open, so it can never be the FIRST
|
|
169
|
+
* step of a self-opened (`Headless`) batch — there is no origin to resolve
|
|
170
|
+
* against yet.
|
|
171
|
+
*/
|
|
172
|
+
path?: string | undefined;
|
|
173
|
+
/**
|
|
174
|
+
* ABSOLUTE `http(s)` URL. Only a target that opens its OWN browser
|
|
175
|
+
* (`InspectTargetKind.Headless`) can honour it: an attached user tab that
|
|
176
|
+
* left the project origin would lose the injected bridge, so the broker
|
|
177
|
+
* refuses a `url` navigate on `InspectTargetKind.UserTab` with an actionable
|
|
178
|
+
* error rather than producing an `off-domain` dead end.
|
|
179
|
+
*/
|
|
180
|
+
url?: string | undefined;
|
|
150
181
|
}
|
|
151
182
|
export interface InspectReloadStep {
|
|
152
183
|
kind: InspectStepKind.Reload;
|
|
@@ -417,6 +448,23 @@ export const INSPECT_BATCH_RESULT_MAX_BYTES = 32 * 1024;
|
|
|
417
448
|
export const INSPECT_READ_DEFAULT_LIMIT = 50;
|
|
418
449
|
export const INSPECT_READ_MAX_LIMIT = 200;
|
|
419
450
|
|
|
451
|
+
/**
|
|
452
|
+
* Max nodes ONE `snapshot` step returns. Shared by every target's executor so
|
|
453
|
+
* a snapshot means the same thing in the user's tab and in the headless
|
|
454
|
+
* browser — the agent's `ref` budget must not depend on which target ran.
|
|
455
|
+
*/
|
|
456
|
+
export const INSPECT_SNAPSHOT_MAX_NODES = 200;
|
|
457
|
+
/**
|
|
458
|
+
* The elements a `snapshot` step collects: interactive controls plus the
|
|
459
|
+
* landmark/heading structure that makes the outline navigable. Shared for the
|
|
460
|
+
* same reason as {@link INSPECT_SNAPSHOT_MAX_NODES}.
|
|
461
|
+
*/
|
|
462
|
+
export const INSPECT_SNAPSHOT_SELECTOR =
|
|
463
|
+
'a[href],button,input,textarea,select,[role],[onclick],' +
|
|
464
|
+
'h1,h2,h3,h4,h5,h6,nav,main,header,footer,form,[data-comment-id]';
|
|
465
|
+
/** Attribute an executor stamps on snapshotted elements to mint a stable `ref`. */
|
|
466
|
+
export const INSPECT_SNAPSHOT_REF_ATTR = 'data-xema-inspect-ref';
|
|
467
|
+
|
|
420
468
|
/** True when the step is a navigation barrier (later steps run post-load). */
|
|
421
469
|
export function isInspectNavigationStep(kind: InspectStepKind): boolean {
|
|
422
470
|
return (
|
|
@@ -425,3 +473,14 @@ export function isInspectNavigationStep(kind: InspectStepKind): boolean {
|
|
|
425
473
|
kind === InspectStepKind.Back
|
|
426
474
|
);
|
|
427
475
|
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Resolve a windowed read's `limit` against the shared default/ceiling. One
|
|
479
|
+
* implementation so every target clamps identically.
|
|
480
|
+
*/
|
|
481
|
+
export function clampInspectReadLimit(limit: number | undefined): number {
|
|
482
|
+
if (limit === undefined || limit <= 0) {
|
|
483
|
+
return INSPECT_READ_DEFAULT_LIMIT;
|
|
484
|
+
}
|
|
485
|
+
return Math.min(limit, INSPECT_READ_MAX_LIMIT);
|
|
486
|
+
}
|
|
@@ -33,11 +33,23 @@ const windowedReadShape = {
|
|
|
33
33
|
limit: z.number().int().positive().optional(),
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Absolute-URL matcher for `navigate.url`. A deliberate literal scheme check
|
|
38
|
+
* rather than a generic "is this a URL" helper: the ONLY schemes an inspect
|
|
39
|
+
* target may open are http(s), and the service re-parses the value anyway.
|
|
40
|
+
*/
|
|
41
|
+
const ABSOLUTE_HTTP_URL = /^https?:\/\//i;
|
|
42
|
+
|
|
43
|
+
const InspectStepVariantSchema = z.discriminatedUnion('kind', [
|
|
37
44
|
z.object({
|
|
38
45
|
kind: z.literal(InspectStepKind.Navigate),
|
|
39
|
-
/**
|
|
40
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Origin-relative path, e.g. `/checkout`. Mutually exclusive with `url`
|
|
48
|
+
* (see the exactly-one refinement below).
|
|
49
|
+
*/
|
|
50
|
+
path: z.string().min(1).max(2000).optional(),
|
|
51
|
+
/** Absolute http(s) URL. Only a self-opened target can honour it. */
|
|
52
|
+
url: z.string().min(1).max(2000).regex(ABSOLUTE_HTTP_URL).optional(),
|
|
41
53
|
}),
|
|
42
54
|
z.object({ kind: z.literal(InspectStepKind.Reload) }),
|
|
43
55
|
z.object({ kind: z.literal(InspectStepKind.Back) }),
|
|
@@ -96,6 +108,27 @@ export const InspectStepSchema = z.discriminatedUnion('kind', [
|
|
|
96
108
|
}),
|
|
97
109
|
]);
|
|
98
110
|
|
|
111
|
+
/**
|
|
112
|
+
* The step validator.
|
|
113
|
+
*
|
|
114
|
+
* The `navigate` verb carries EXACTLY ONE of `path` / `url`. That is enforced
|
|
115
|
+
* here, at the single source of truth, so no executor has to guess what an
|
|
116
|
+
* empty or doubly-specified navigate means. `path` and `url` are NOT
|
|
117
|
+
* interchangeable spellings of the same thing: `path` is an in-origin move a
|
|
118
|
+
* user tab can follow, `url` is an origin change only a self-opened
|
|
119
|
+
* (headless) target can honour.
|
|
120
|
+
*/
|
|
121
|
+
export const InspectStepSchema = InspectStepVariantSchema.refine(
|
|
122
|
+
(step) =>
|
|
123
|
+
step.kind !== InspectStepKind.Navigate ||
|
|
124
|
+
(step.path === undefined) !== (step.url === undefined),
|
|
125
|
+
{
|
|
126
|
+
message:
|
|
127
|
+
'A "navigate" step must carry exactly one of `path` (origin-relative, e.g. "/checkout") ' +
|
|
128
|
+
'or `url` (absolute http(s), only honoured by a self-opened target such as "headless").',
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
|
|
99
132
|
/**
|
|
100
133
|
* Compile-time drift guard: the schema and the hand-authored `InspectStep`
|
|
101
134
|
* union MUST stay mutually assignable. Add a step kind (or change a field) on
|
package/src/search/index.ts
CHANGED