oh-my-knowledge 0.51.2 → 0.52.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/README.md +27 -6
- package/README.zh.md +27 -6
- package/dist/assets/agent-skills/omk/SKILL.md +8 -8
- package/dist/observability/codex-conversation-index.d.ts +88 -0
- package/dist/observability/codex-conversation-index.js +566 -0
- package/dist/observability/codex-protocol.d.ts +12 -0
- package/dist/observability/codex-protocol.js +78 -0
- package/dist/observability/codex-tool-status.d.ts +16 -0
- package/dist/observability/codex-tool-status.js +114 -0
- package/dist/observability/codex-trace-adapter.js +342 -119
- package/dist/observability/conversation-catalog.d.ts +38 -0
- package/dist/observability/conversation-catalog.js +573 -0
- package/dist/observability/conversation-index-process.d.ts +1 -0
- package/dist/observability/conversation-index-process.js +31 -0
- package/dist/observability/conversation-view-model.d.ts +5 -0
- package/dist/observability/conversation-view-model.js +100 -0
- package/dist/observability/experience.d.ts +3 -1
- package/dist/observability/experience.js +248 -7
- package/dist/observability/inbox.js +40 -2
- package/dist/observability/knowledge-debugger.d.ts +4 -0
- package/dist/observability/knowledge-debugger.js +364 -0
- package/dist/observability/polling-subscription-hub.d.ts +27 -0
- package/dist/observability/polling-subscription-hub.js +149 -0
- package/dist/observability/source-record-archive.d.ts +13 -0
- package/dist/observability/source-record-archive.js +324 -0
- package/dist/observability/task-window.d.ts +8 -0
- package/dist/observability/task-window.js +36 -0
- package/dist/observability/trace-ir.d.ts +66 -1
- package/dist/observability/trace-source.d.ts +1 -0
- package/dist/observability/trace-source.js +12 -5
- package/dist/observability/turn-index.d.ts +3 -0
- package/dist/observability/turn-index.js +251 -0
- package/dist/renderer/conversation-renderer.d.ts +9 -0
- package/dist/renderer/conversation-renderer.js +410 -0
- package/dist/renderer/icons.js +1 -0
- package/dist/renderer/inline-markdown.d.ts +6 -0
- package/dist/renderer/inline-markdown.js +158 -0
- package/dist/renderer/knowledge-debugger-renderer.d.ts +9 -0
- package/dist/renderer/knowledge-debugger-renderer.js +2280 -0
- package/dist/renderer/observation-inbox-renderer.js +9 -0
- package/dist/renderer/skill-list-renderer.js +2 -1
- package/dist/renderer/trajectory-live.d.ts +42 -0
- package/dist/renderer/trajectory-live.js +258 -0
- package/dist/renderer/trajectory-routing.d.ts +60 -0
- package/dist/renderer/trajectory-routing.js +351 -0
- package/dist/server/report-server.d.ts +4 -1
- package/dist/server/report-server.js +274 -6
- package/dist/types/observability.d.ts +225 -1
- package/package.json +8 -5
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
export function planFlowMarkerProgresses(pathLength, markerCount) {
|
|
2
|
+
if (!Number.isFinite(pathLength) || pathLength <= 0 || !Number.isFinite(markerCount) || markerCount <= 0)
|
|
3
|
+
return [];
|
|
4
|
+
const length = Math.max(1, pathLength);
|
|
5
|
+
const count = Math.max(1, Math.floor(markerCount));
|
|
6
|
+
const minimumEndpointOffset = Math.min(18, length / 2);
|
|
7
|
+
const closestDistanceFromEnd = Math.max(minimumEndpointOffset, Math.min(28, length * .28));
|
|
8
|
+
const furthestDistanceFromEnd = Math.max(closestDistanceFromEnd, length - minimumEndpointOffset);
|
|
9
|
+
const spacing = count > 1
|
|
10
|
+
? Math.min(34, (furthestDistanceFromEnd - closestDistanceFromEnd) / (count - 1))
|
|
11
|
+
: 0;
|
|
12
|
+
return Array.from({ length: count }, (_value, markerIndex) => {
|
|
13
|
+
const distanceFromEnd = closestDistanceFromEnd + spacing * (count - markerIndex - 1);
|
|
14
|
+
return Math.max(0, Math.min(1, 1 - distanceFromEnd / length));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export function createHorizontalObstacleIndex(rects, bucketSize = 240) {
|
|
18
|
+
const safeBucketSize = Math.max(32, bucketSize);
|
|
19
|
+
const buckets = new Map();
|
|
20
|
+
rects.forEach((rect) => {
|
|
21
|
+
const firstBucket = Math.floor(rect.left / safeBucketSize);
|
|
22
|
+
const lastBucket = Math.floor(rect.right / safeBucketSize);
|
|
23
|
+
for (let bucket = firstBucket; bucket <= lastBucket; bucket += 1) {
|
|
24
|
+
const entries = buckets.get(bucket) ?? [];
|
|
25
|
+
entries.push(rect);
|
|
26
|
+
buckets.set(bucket, entries);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return { bucketSize: safeBucketSize, buckets, all: rects };
|
|
30
|
+
}
|
|
31
|
+
export function queryHorizontalObstacleIndex(index, minX, maxX, minY = Number.NEGATIVE_INFINITY, maxY = Number.POSITIVE_INFINITY) {
|
|
32
|
+
const left = Math.min(minX, maxX);
|
|
33
|
+
const right = Math.max(minX, maxX);
|
|
34
|
+
const top = Math.min(minY, maxY);
|
|
35
|
+
const bottom = Math.max(minY, maxY);
|
|
36
|
+
const firstBucket = Math.floor(left / index.bucketSize);
|
|
37
|
+
const lastBucket = Math.floor(right / index.bucketSize);
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const matches = [];
|
|
40
|
+
for (let bucket = firstBucket; bucket <= lastBucket; bucket += 1) {
|
|
41
|
+
for (const rect of index.buckets.get(bucket) ?? []) {
|
|
42
|
+
if (seen.has(rect))
|
|
43
|
+
continue;
|
|
44
|
+
seen.add(rect);
|
|
45
|
+
if (rect.right < left || rect.left > right || rect.bottom < top || rect.top > bottom)
|
|
46
|
+
continue;
|
|
47
|
+
matches.push(rect);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return matches;
|
|
51
|
+
}
|
|
52
|
+
export function routingPointInsideRect(point, rect) {
|
|
53
|
+
return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
|
54
|
+
}
|
|
55
|
+
export function routingLineHitsRect(fromPoint, toPoint, rect) {
|
|
56
|
+
if (routingPointInsideRect(fromPoint, rect) || routingPointInsideRect(toPoint, rect))
|
|
57
|
+
return true;
|
|
58
|
+
const direction = { x: toPoint.x - fromPoint.x, y: toPoint.y - fromPoint.y };
|
|
59
|
+
let entry = 0;
|
|
60
|
+
let exit = 1;
|
|
61
|
+
const boundaries = [
|
|
62
|
+
{ coefficient: -direction.x, distance: fromPoint.x - rect.left },
|
|
63
|
+
{ coefficient: direction.x, distance: rect.right - fromPoint.x },
|
|
64
|
+
{ coefficient: -direction.y, distance: fromPoint.y - rect.top },
|
|
65
|
+
{ coefficient: direction.y, distance: rect.bottom - fromPoint.y },
|
|
66
|
+
];
|
|
67
|
+
for (const boundary of boundaries) {
|
|
68
|
+
if (boundary.coefficient === 0) {
|
|
69
|
+
if (boundary.distance < 0)
|
|
70
|
+
return false;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const ratio = boundary.distance / boundary.coefficient;
|
|
74
|
+
if (boundary.coefficient < 0)
|
|
75
|
+
entry = Math.max(entry, ratio);
|
|
76
|
+
else
|
|
77
|
+
exit = Math.min(exit, ratio);
|
|
78
|
+
if (entry > exit)
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return entry <= exit && exit >= 0 && entry <= 1;
|
|
82
|
+
}
|
|
83
|
+
export function routingQuadraticHitsRect(fromPoint, control, toPoint, rect) {
|
|
84
|
+
const minX = Math.min(fromPoint.x, control.x, toPoint.x);
|
|
85
|
+
const maxX = Math.max(fromPoint.x, control.x, toPoint.x);
|
|
86
|
+
const minY = Math.min(fromPoint.y, control.y, toPoint.y);
|
|
87
|
+
const maxY = Math.max(fromPoint.y, control.y, toPoint.y);
|
|
88
|
+
if (rect.right < minX || rect.left > maxX || rect.bottom < minY || rect.top > maxY)
|
|
89
|
+
return false;
|
|
90
|
+
for (let sampleIndex = 1; sampleIndex < 40; sampleIndex += 1) {
|
|
91
|
+
const progress = sampleIndex / 40;
|
|
92
|
+
const inverse = 1 - progress;
|
|
93
|
+
const x = inverse * inverse * fromPoint.x + 2 * inverse * progress * control.x + progress * progress * toPoint.x;
|
|
94
|
+
const y = inverse * inverse * fromPoint.y + 2 * inverse * progress * control.y + progress * progress * toPoint.y;
|
|
95
|
+
if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom)
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
export function routingMoveToward(fromPoint, toPoint, distance) {
|
|
101
|
+
const dx = toPoint.x - fromPoint.x;
|
|
102
|
+
const dy = toPoint.y - fromPoint.y;
|
|
103
|
+
const length = Math.hypot(dx, dy) || 1;
|
|
104
|
+
return {
|
|
105
|
+
x: fromPoint.x + dx / length * distance,
|
|
106
|
+
y: fromPoint.y + dy / length * distance,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
export function routingEdgePoint(rect, targetX, targetY) {
|
|
110
|
+
const centerX = (rect.left + rect.right) / 2;
|
|
111
|
+
const centerY = (rect.top + rect.bottom) / 2;
|
|
112
|
+
const dx = targetX - centerX;
|
|
113
|
+
const dy = targetY - centerY;
|
|
114
|
+
const width = rect.right - rect.left;
|
|
115
|
+
const height = rect.bottom - rect.top;
|
|
116
|
+
const scaleX = dx === 0 ? Number.POSITIVE_INFINITY : (width / 2) / Math.abs(dx);
|
|
117
|
+
const scaleY = dy === 0 ? Number.POSITIVE_INFINITY : (height / 2) / Math.abs(dy);
|
|
118
|
+
const scale = Math.min(scaleX, scaleY);
|
|
119
|
+
return { x: centerX + dx * scale, y: centerY + dy * scale };
|
|
120
|
+
}
|
|
121
|
+
export function routingConnectionPoints(fromRect, toRect) {
|
|
122
|
+
const fromCenter = { x: (fromRect.left + fromRect.right) / 2, y: (fromRect.top + fromRect.bottom) / 2 };
|
|
123
|
+
const toCenter = { x: (toRect.left + toRect.right) / 2, y: (toRect.top + toRect.bottom) / 2 };
|
|
124
|
+
const from = routingEdgePoint(fromRect, toCenter.x, toCenter.y);
|
|
125
|
+
const to = routingEdgePoint(toRect, fromCenter.x, fromCenter.y);
|
|
126
|
+
return {
|
|
127
|
+
from: routingMoveToward(from, toCenter, 2),
|
|
128
|
+
to: routingMoveToward(to, fromCenter, 2),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export function routingRectPort(rect, side) {
|
|
132
|
+
const centerX = (rect.left + rect.right) / 2;
|
|
133
|
+
const centerY = (rect.top + rect.bottom) / 2;
|
|
134
|
+
if (side === 'left')
|
|
135
|
+
return { x: rect.left, y: centerY };
|
|
136
|
+
if (side === 'right')
|
|
137
|
+
return { x: rect.right, y: centerY };
|
|
138
|
+
if (side === 'top')
|
|
139
|
+
return { x: centerX, y: rect.top };
|
|
140
|
+
return { x: centerX, y: rect.bottom };
|
|
141
|
+
}
|
|
142
|
+
export function routingFlowControlPoint(points, requestedBend, side = 1) {
|
|
143
|
+
const dx = points.to.x - points.from.x;
|
|
144
|
+
const dy = points.to.y - points.from.y;
|
|
145
|
+
const length = Math.hypot(dx, dy) || 1;
|
|
146
|
+
const normalX = -dy / length;
|
|
147
|
+
const normalY = dx / length;
|
|
148
|
+
const forwardAdvance = Math.max(0, dx);
|
|
149
|
+
const naturalBend = Math.min(12, length * .06, forwardAdvance * .45);
|
|
150
|
+
const bend = requestedBend ?? naturalBend;
|
|
151
|
+
const bendDirection = normalX === 0 ? 1 : Math.sign(normalX);
|
|
152
|
+
return {
|
|
153
|
+
x: (points.from.x + points.to.x) / 2 + normalX * bend * bendDirection * side,
|
|
154
|
+
y: (points.from.y + points.to.y) / 2 + normalY * bend * bendDirection * side,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
export function routingRoundedPolylinePath(routePoints, radius = 10) {
|
|
158
|
+
if (routePoints.length < 2)
|
|
159
|
+
return '';
|
|
160
|
+
let d = `M ${routePoints[0].x} ${routePoints[0].y}`;
|
|
161
|
+
for (let pointIndex = 1; pointIndex < routePoints.length - 1; pointIndex += 1) {
|
|
162
|
+
const previous = routePoints[pointIndex - 1];
|
|
163
|
+
const corner = routePoints[pointIndex];
|
|
164
|
+
const next = routePoints[pointIndex + 1];
|
|
165
|
+
const cornerRadius = Math.min(radius, Math.hypot(corner.x - previous.x, corner.y - previous.y) / 2, Math.hypot(next.x - corner.x, next.y - corner.y) / 2);
|
|
166
|
+
const entry = routingMoveToward(corner, previous, cornerRadius);
|
|
167
|
+
const exit = routingMoveToward(corner, next, cornerRadius);
|
|
168
|
+
d += ` L ${entry.x} ${entry.y} Q ${corner.x} ${corner.y} ${exit.x} ${exit.y}`;
|
|
169
|
+
}
|
|
170
|
+
const last = routePoints[routePoints.length - 1];
|
|
171
|
+
return `${d} L ${last.x} ${last.y}`;
|
|
172
|
+
}
|
|
173
|
+
export function planFlowRoute(request) {
|
|
174
|
+
const { fromRect, toRect, fromLane, toLane, obstacleIndex, fromOwner, toOwner } = request;
|
|
175
|
+
const metrics = {
|
|
176
|
+
obstacleQueries: 0,
|
|
177
|
+
obstacleCandidates: 0,
|
|
178
|
+
collisionChecks: 0,
|
|
179
|
+
curveCandidates: 0,
|
|
180
|
+
corridorCandidates: 0,
|
|
181
|
+
};
|
|
182
|
+
const queryObstacles = (minX, maxX, minY, maxY) => {
|
|
183
|
+
metrics.obstacleQueries += 1;
|
|
184
|
+
const matches = queryHorizontalObstacleIndex(obstacleIndex, minX, maxX, minY, maxY)
|
|
185
|
+
.filter((rect) => rect.owner !== fromOwner && rect.owner !== toOwner);
|
|
186
|
+
metrics.obstacleCandidates += matches.length;
|
|
187
|
+
return matches;
|
|
188
|
+
};
|
|
189
|
+
const lineIsClear = (from, to) => {
|
|
190
|
+
const candidates = queryObstacles(from.x, to.x, from.y, to.y);
|
|
191
|
+
return !candidates.some((rect) => {
|
|
192
|
+
metrics.collisionChecks += 1;
|
|
193
|
+
return routingLineHitsRect(from, to, rect);
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
const points = routingConnectionPoints(fromRect, toRect);
|
|
197
|
+
const direct = fromLane === toLane && Math.abs(points.to.y - points.from.y) < 4;
|
|
198
|
+
if (direct && lineIsClear(points.from, points.to)) {
|
|
199
|
+
return {
|
|
200
|
+
routeKind: 'straight',
|
|
201
|
+
d: `M ${points.from.x} ${points.from.y} L ${points.to.x} ${points.to.y}`,
|
|
202
|
+
from: points.from,
|
|
203
|
+
to: points.to,
|
|
204
|
+
arrowFrom: points.from,
|
|
205
|
+
metrics,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const fromCenter = { x: (fromRect.left + fromRect.right) / 2, y: (fromRect.top + fromRect.bottom) / 2 };
|
|
209
|
+
const toCenter = { x: (toRect.left + toRect.right) / 2, y: (toRect.top + toRect.bottom) / 2 };
|
|
210
|
+
const verticalFromSide = toCenter.y < fromCenter.y ? 'top' : 'bottom';
|
|
211
|
+
const verticalToSide = toCenter.y < fromCenter.y ? 'bottom' : 'top';
|
|
212
|
+
const horizontalFromSide = toCenter.x < fromCenter.x ? 'left' : 'right';
|
|
213
|
+
const horizontalToSide = toCenter.x < fromCenter.x ? 'right' : 'left';
|
|
214
|
+
const pointPairs = [
|
|
215
|
+
{ points, penalty: 0 },
|
|
216
|
+
{ points: { from: routingRectPort(fromRect, horizontalFromSide), to: routingRectPort(toRect, verticalToSide) }, penalty: 8 },
|
|
217
|
+
{ points: { from: routingRectPort(fromRect, verticalFromSide), to: routingRectPort(toRect, verticalToSide) }, penalty: 12 },
|
|
218
|
+
{ points: { from: routingRectPort(fromRect, horizontalFromSide), to: routingRectPort(toRect, horizontalToSide) }, penalty: 14 },
|
|
219
|
+
{
|
|
220
|
+
points: {
|
|
221
|
+
from: routingRectPort(fromRect, horizontalFromSide === 'left' ? 'right' : 'left'),
|
|
222
|
+
to: routingRectPort(toRect, verticalToSide),
|
|
223
|
+
},
|
|
224
|
+
penalty: 22,
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
const bendCandidates = [
|
|
228
|
+
{ bend: undefined, side: 1, penalty: 0 },
|
|
229
|
+
...[20, 32, 48, 68, 92, 120, 156, 198].map((bend) => ({ bend, side: 1, penalty: bend * .18 })),
|
|
230
|
+
...[20, 32, 48, 68, 92, 120, 156, 198].map((bend) => ({ bend, side: -1, penalty: 24 + bend * .2 })),
|
|
231
|
+
];
|
|
232
|
+
const curveCandidates = pointPairs.flatMap((pair) => bendCandidates.map((bendCandidate) => {
|
|
233
|
+
const control = routingFlowControlPoint(pair.points, bendCandidate.bend, bendCandidate.side);
|
|
234
|
+
const distance = Math.hypot(pair.points.to.x - pair.points.from.x, pair.points.to.y - pair.points.from.y);
|
|
235
|
+
return {
|
|
236
|
+
...pair.points,
|
|
237
|
+
control,
|
|
238
|
+
score: distance + pair.penalty + bendCandidate.penalty,
|
|
239
|
+
};
|
|
240
|
+
})).sort((left, right) => left.score - right.score);
|
|
241
|
+
for (const candidate of curveCandidates) {
|
|
242
|
+
metrics.curveCandidates += 1;
|
|
243
|
+
const obstacles = queryObstacles(Math.min(candidate.from.x, candidate.control.x, candidate.to.x), Math.max(candidate.from.x, candidate.control.x, candidate.to.x), Math.min(candidate.from.y, candidate.control.y, candidate.to.y), Math.max(candidate.from.y, candidate.control.y, candidate.to.y));
|
|
244
|
+
const blocked = obstacles.some((rect) => {
|
|
245
|
+
metrics.collisionChecks += 1;
|
|
246
|
+
return routingQuadraticHitsRect(candidate.from, candidate.control, candidate.to, rect);
|
|
247
|
+
});
|
|
248
|
+
if (!blocked) {
|
|
249
|
+
return {
|
|
250
|
+
routeKind: 'quadratic',
|
|
251
|
+
d: `M ${candidate.from.x} ${candidate.from.y} Q ${candidate.control.x} ${candidate.control.y} ${candidate.to.x} ${candidate.to.y}`,
|
|
252
|
+
from: candidate.from,
|
|
253
|
+
to: candidate.to,
|
|
254
|
+
arrowFrom: candidate.control,
|
|
255
|
+
metrics,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (fromLane === toLane)
|
|
260
|
+
return undefined;
|
|
261
|
+
const allObstacles = obstacleIndex.all.filter((rect) => rect.owner !== fromOwner && rect.owner !== toOwner);
|
|
262
|
+
const verticalTop = Math.min(points.from.y, points.to.y);
|
|
263
|
+
const verticalBottom = Math.max(points.from.y, points.to.y);
|
|
264
|
+
const intervals = allObstacles
|
|
265
|
+
.filter((rect) => rect.bottom >= verticalTop && rect.top <= verticalBottom)
|
|
266
|
+
.map((rect) => ({ left: rect.left, right: rect.right }))
|
|
267
|
+
.sort((left, right) => left.left - right.left)
|
|
268
|
+
.reduce((merged, interval) => {
|
|
269
|
+
const previous = merged[merged.length - 1];
|
|
270
|
+
if (!previous || interval.left > previous.right)
|
|
271
|
+
merged.push({ ...interval });
|
|
272
|
+
else
|
|
273
|
+
previous.right = Math.max(previous.right, interval.right);
|
|
274
|
+
return merged;
|
|
275
|
+
}, []);
|
|
276
|
+
const corridorXs = [points.from.x, points.to.x, (points.from.x + points.to.x) / 2];
|
|
277
|
+
intervals.forEach((interval, intervalIndex) => {
|
|
278
|
+
const next = intervals[intervalIndex + 1];
|
|
279
|
+
if (next && next.left > interval.right)
|
|
280
|
+
corridorXs.push((interval.right + next.left) / 2);
|
|
281
|
+
});
|
|
282
|
+
if (intervals.length > 0) {
|
|
283
|
+
corridorXs.push(intervals[0].left - 16, intervals[0].left - 44, intervals[0].left - 76, intervals[intervals.length - 1].right + 16, intervals[intervals.length - 1].right + 44, intervals[intervals.length - 1].right + 76);
|
|
284
|
+
}
|
|
285
|
+
const corridorPort = (rect, side, corridorX) => {
|
|
286
|
+
const inset = Math.min(14, (rect.right - rect.left) / 4);
|
|
287
|
+
const centerY = (rect.top + rect.bottom) / 2;
|
|
288
|
+
if (corridorX < rect.left + inset)
|
|
289
|
+
return { x: rect.left - 2, y: centerY };
|
|
290
|
+
if (corridorX > rect.right - inset)
|
|
291
|
+
return { x: rect.right + 2, y: centerY };
|
|
292
|
+
return {
|
|
293
|
+
x: Math.max(rect.left + inset, Math.min(rect.right - inset, corridorX)),
|
|
294
|
+
y: (side === 'top' ? rect.top : rect.bottom) + (side === 'top' ? -2 : 2),
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
let bestCorridor;
|
|
298
|
+
for (const corridorX of [...new Set(corridorXs.map((value) => Math.round(value * 10) / 10))]) {
|
|
299
|
+
metrics.corridorCandidates += 1;
|
|
300
|
+
const fromPoint = corridorPort(fromRect, verticalFromSide, corridorX);
|
|
301
|
+
const toPoint = corridorPort(toRect, verticalToSide, corridorX);
|
|
302
|
+
const routePoints = [fromPoint, { x: corridorX, y: fromPoint.y }, { x: corridorX, y: toPoint.y }, toPoint]
|
|
303
|
+
.filter((point, pointIndex, pointsList) => pointIndex === 0
|
|
304
|
+
|| Math.hypot(point.x - pointsList[pointIndex - 1].x, point.y - pointsList[pointIndex - 1].y) > 1);
|
|
305
|
+
const segments = routePoints.slice(1).map((point, pointIndex) => ({ from: routePoints[pointIndex], to: point }));
|
|
306
|
+
let blocked = false;
|
|
307
|
+
for (const segment of segments) {
|
|
308
|
+
if (!lineIsClear(segment.from, segment.to)) {
|
|
309
|
+
blocked = true;
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (blocked)
|
|
314
|
+
continue;
|
|
315
|
+
const routeLength = segments.reduce((sum, segment) => sum
|
|
316
|
+
+ Math.hypot(segment.to.x - segment.from.x, segment.to.y - segment.from.y), 0);
|
|
317
|
+
const backward = Math.max(0, Math.min(fromCenter.x, toCenter.x) - corridorX);
|
|
318
|
+
const score = routeLength + backward * .3;
|
|
319
|
+
if (!bestCorridor || score < bestCorridor.score) {
|
|
320
|
+
bestCorridor = { routePoints, from: fromPoint, to: toPoint, score };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!bestCorridor)
|
|
324
|
+
return undefined;
|
|
325
|
+
return {
|
|
326
|
+
routeKind: 'corridor',
|
|
327
|
+
d: routingRoundedPolylinePath(bestCorridor.routePoints),
|
|
328
|
+
from: bestCorridor.from,
|
|
329
|
+
to: bestCorridor.to,
|
|
330
|
+
arrowFrom: bestCorridor.routePoints[bestCorridor.routePoints.length - 2],
|
|
331
|
+
metrics,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
export function renderTrajectoryRoutingClientSource() {
|
|
335
|
+
// Studio 页面没有独立的客户端打包链路;序列化已类型检查的纯函数,避免维护第二份浏览器路由实现。
|
|
336
|
+
return [
|
|
337
|
+
planFlowMarkerProgresses,
|
|
338
|
+
createHorizontalObstacleIndex,
|
|
339
|
+
queryHorizontalObstacleIndex,
|
|
340
|
+
routingPointInsideRect,
|
|
341
|
+
routingLineHitsRect,
|
|
342
|
+
routingQuadraticHitsRect,
|
|
343
|
+
routingMoveToward,
|
|
344
|
+
routingEdgePoint,
|
|
345
|
+
routingConnectionPoints,
|
|
346
|
+
routingRectPort,
|
|
347
|
+
routingFlowControlPoint,
|
|
348
|
+
routingRoundedPolylinePath,
|
|
349
|
+
planFlowRoute,
|
|
350
|
+
].map((fn) => fn.toString()).join('\n');
|
|
351
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JobStore, ReportStore } from '../types/index.js';
|
|
2
|
+
import { type ConversationCatalog } from '../observability/conversation-catalog.js';
|
|
2
3
|
interface ReportServerOptions {
|
|
3
4
|
port?: number;
|
|
4
5
|
/** 监听 host。默认 '127.0.0.1'(只允许本机访问,容器/远程场景看不到)。
|
|
@@ -19,6 +20,8 @@ interface ReportServerOptions {
|
|
|
19
20
|
managedDir?: string | (() => string);
|
|
20
21
|
store?: ReportStore;
|
|
21
22
|
jobStore?: JobStore;
|
|
23
|
+
/** Source-neutral conversation inventory. Defaults to the local Codex catalog. */
|
|
24
|
+
conversationCatalog?: ConversationCatalog;
|
|
22
25
|
/** 是否把别项目的 observe-health 索引卡片合进列表 / 详情 / skill 首页(机器级总览)。
|
|
23
26
|
* 默认 false(固定目录 / 测试 hermetic);studio 仅在「无 --analyses-dir 且无 --global」的默认机器级模式传 true。 */
|
|
24
27
|
includeObserveCards?: boolean;
|
|
@@ -32,5 +35,5 @@ interface ReportServer {
|
|
|
32
35
|
getUrl(): string | null;
|
|
33
36
|
}
|
|
34
37
|
export declare function formatListenError(p: number, err: unknown): Error | null;
|
|
35
|
-
export declare function createReportServer({ port, host: hostOption, reportsDir, analysesDir, doctorsDir, observationsDir, jobsDir, managedDir, store, jobStore, includeObserveCards, includeDoctorCards }?: ReportServerOptions): ReportServer;
|
|
38
|
+
export declare function createReportServer({ port, host: hostOption, reportsDir, analysesDir, doctorsDir, observationsDir, jobsDir, managedDir, store, jobStore, conversationCatalog, includeObserveCards, includeDoctorCards }?: ReportServerOptions): ReportServer;
|
|
36
39
|
export {};
|