@blueharford/scrypted-spatial-awareness 0.6.14 → 0.6.16
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/main.nodejs.js +1 -1
- package/dist/main.nodejs.js.map +1 -1
- package/dist/plugin.zip +0 -0
- package/out/main.nodejs.js +244 -40
- package/out/main.nodejs.js.map +1 -1
- package/out/plugin.zip +0 -0
- package/package.json +1 -1
- package/src/core/topology-discovery.ts +238 -40
- package/src/models/discovery.ts +17 -0
package/dist/plugin.zip
CHANGED
|
Binary file
|
package/out/main.nodejs.js
CHANGED
|
@@ -36173,59 +36173,140 @@ const topology_1 = __webpack_require__(/*! ../models/topology */ "./src/models/t
|
|
|
36173
36173
|
const spatial_reasoning_1 = __webpack_require__(/*! ./spatial-reasoning */ "./src/core/spatial-reasoning.ts");
|
|
36174
36174
|
const { systemManager } = sdk_1.default;
|
|
36175
36175
|
/** Scene analysis prompt for single camera */
|
|
36176
|
-
const SCENE_ANALYSIS_PROMPT = `
|
|
36176
|
+
const SCENE_ANALYSIS_PROMPT = `You are analyzing a security camera image. Describe EVERYTHING you can see in detail.
|
|
36177
|
+
|
|
36178
|
+
## INSTRUCTIONS
|
|
36179
|
+
Look at this image carefully and identify ALL visible objects, structures, and areas. Be thorough - even small or partially visible items are important for security awareness.
|
|
36180
|
+
|
|
36181
|
+
## 1. LANDMARKS - List EVERY distinct object or feature you can see:
|
|
36182
|
+
|
|
36183
|
+
**Structures** (buildings, parts of buildings):
|
|
36184
|
+
- Houses, garages, sheds, porches, decks, patios, carports, gazebos
|
|
36185
|
+
- Walls, pillars, columns, railings, stairs, steps
|
|
36186
|
+
|
|
36187
|
+
**Vegetation** (plants, trees, landscaping):
|
|
36188
|
+
- Trees (describe type if identifiable: oak, palm, pine, etc.)
|
|
36189
|
+
- Bushes, shrubs, hedges
|
|
36190
|
+
- Flower beds, gardens, planters, potted plants
|
|
36191
|
+
- Grass/lawn areas, mulch beds
|
|
36192
|
+
|
|
36193
|
+
**Boundaries & Barriers**:
|
|
36194
|
+
- Fences (wood, chain-link, aluminum, vinyl, iron, privacy)
|
|
36195
|
+
- Walls (brick, stone, concrete, retaining)
|
|
36196
|
+
- Gates, gate posts
|
|
36197
|
+
- Hedges used as boundaries
|
|
36198
|
+
|
|
36199
|
+
**Access Points & Pathways**:
|
|
36200
|
+
- Doors (front, side, garage, screen)
|
|
36201
|
+
- Driveways (concrete, asphalt, gravel, pavers)
|
|
36202
|
+
- Walkways, sidewalks, paths, stepping stones
|
|
36203
|
+
- Stairs, ramps, porches
|
|
36204
|
+
|
|
36205
|
+
**Utility & Fixtures**:
|
|
36206
|
+
- Mailboxes, package boxes
|
|
36207
|
+
- Light fixtures, lamp posts, solar lights
|
|
36208
|
+
- A/C units, utility boxes, meters
|
|
36209
|
+
- Trash cans, recycling bins
|
|
36210
|
+
- Hoses, spigots, sprinklers
|
|
36211
|
+
|
|
36212
|
+
**Outdoor Items**:
|
|
36213
|
+
- Vehicles (cars, trucks, motorcycles, boats, trailers)
|
|
36214
|
+
- Furniture (chairs, tables, benches, swings)
|
|
36215
|
+
- Grills, fire pits, outdoor kitchens
|
|
36216
|
+
- Play equipment, trampolines, pools
|
|
36217
|
+
- Decorations, flags, signs
|
|
36218
|
+
|
|
36219
|
+
**Off-Property Elements** (important for security context):
|
|
36220
|
+
- Street, road, sidewalk
|
|
36221
|
+
- Neighbor's property/fence/house
|
|
36222
|
+
- Public areas visible
|
|
36223
|
+
|
|
36224
|
+
For EACH landmark, estimate its DISTANCE from the camera:
|
|
36225
|
+
- "close" = 0-10 feet (within arm's reach of camera)
|
|
36226
|
+
- "near" = 10-30 feet
|
|
36227
|
+
- "medium" = 30-60 feet
|
|
36228
|
+
- "far" = 60-100 feet
|
|
36229
|
+
- "distant" = 100+ feet (edge of property or beyond)
|
|
36230
|
+
|
|
36231
|
+
## 2. ZONES - Identify distinct AREAS visible:
|
|
36232
|
+
- Front yard, backyard, side yard
|
|
36233
|
+
- Driveway, parking area
|
|
36234
|
+
- Patio, deck, porch
|
|
36235
|
+
- Garden area, lawn
|
|
36236
|
+
- Street/road
|
|
36237
|
+
- Neighbor's yard
|
|
36238
|
+
|
|
36239
|
+
For each zone, estimate what percentage of the image it covers (0.0 to 1.0).
|
|
36240
|
+
|
|
36241
|
+
## 3. EDGES - What's at each edge of the frame:
|
|
36242
|
+
This helps understand what's just out of view.
|
|
36243
|
+
|
|
36244
|
+
## 4. CAMERA CONTEXT:
|
|
36245
|
+
- Estimated mounting height (ground level, 8ft, 12ft, roofline, etc.)
|
|
36246
|
+
- Approximate field of view (narrow, medium, wide)
|
|
36247
|
+
- Facing direction if determinable (north, south, street-facing, etc.)
|
|
36177
36248
|
|
|
36178
|
-
|
|
36179
|
-
- Structures (house, garage, shed, porch, deck)
|
|
36180
|
-
- Features (mailbox, tree, pool, garden, fountain)
|
|
36181
|
-
- Access points (door, gate, driveway entrance, walkway)
|
|
36182
|
-
- Boundaries (fence, wall, hedge)
|
|
36183
|
-
|
|
36184
|
-
2. ZONES - Identify area types visible:
|
|
36185
|
-
- What type of area is this? (front yard, backyard, driveway, street, patio, walkway)
|
|
36186
|
-
- Estimate what percentage of the frame each zone covers (0.0 to 1.0)
|
|
36187
|
-
|
|
36188
|
-
3. EDGES - What's visible at the frame edges:
|
|
36189
|
-
- Top edge: (sky, roof, trees, etc.)
|
|
36190
|
-
- Left edge: (fence, neighbor, street, etc.)
|
|
36191
|
-
- Right edge: (fence, garage, etc.)
|
|
36192
|
-
- Bottom edge: (ground, driveway, grass, etc.)
|
|
36193
|
-
|
|
36194
|
-
4. ORIENTATION - Estimate camera facing direction based on shadows, sun position, or landmarks
|
|
36195
|
-
|
|
36196
|
-
Respond with ONLY valid JSON in this exact format:
|
|
36249
|
+
Respond with ONLY valid JSON:
|
|
36197
36250
|
{
|
|
36198
36251
|
"landmarks": [
|
|
36199
|
-
{"name": "
|
|
36252
|
+
{"name": "Mailbox", "type": "feature", "distance": "medium", "confidence": 0.95, "description": "Black metal mailbox on wooden post, approximately 40 feet from camera"},
|
|
36253
|
+
{"name": "Aluminum Fence", "type": "boundary", "distance": "near", "confidence": 0.9, "description": "Silver aluminum fence running along left side of property, about 15-20 feet away"},
|
|
36254
|
+
{"name": "Large Oak Tree", "type": "feature", "distance": "far", "confidence": 0.85, "description": "Mature oak tree near property line, roughly 80 feet from camera"}
|
|
36200
36255
|
],
|
|
36201
36256
|
"zones": [
|
|
36202
|
-
{"name": "Front Yard", "type": "yard", "coverage": 0.
|
|
36257
|
+
{"name": "Front Yard", "type": "yard", "coverage": 0.5, "description": "Grass lawn with some bare patches"},
|
|
36258
|
+
{"name": "Driveway", "type": "driveway", "coverage": 0.25, "description": "Concrete driveway leading to garage"}
|
|
36203
36259
|
],
|
|
36204
|
-
"edges": {
|
|
36205
|
-
|
|
36206
|
-
|
|
36260
|
+
"edges": {
|
|
36261
|
+
"top": "sky, tree canopy",
|
|
36262
|
+
"left": "aluminum fence, neighbor's yard beyond",
|
|
36263
|
+
"right": "side of house, garage door",
|
|
36264
|
+
"bottom": "concrete walkway, grass edge"
|
|
36265
|
+
},
|
|
36266
|
+
"cameraContext": {
|
|
36267
|
+
"mountHeight": "8 feet",
|
|
36268
|
+
"fieldOfView": "wide",
|
|
36269
|
+
"facingDirection": "street-facing"
|
|
36270
|
+
}
|
|
36271
|
+
}
|
|
36272
|
+
|
|
36273
|
+
BE THOROUGH. List every distinct item you can identify. A typical outdoor scene should have 5-15+ landmarks.`;
|
|
36207
36274
|
/** Multi-camera correlation prompt */
|
|
36208
|
-
const CORRELATION_PROMPT = `I have scene analyses from multiple security cameras at the same property. Help me
|
|
36275
|
+
const CORRELATION_PROMPT = `I have detailed scene analyses from multiple security cameras at the same property. Help me understand which landmarks appear in multiple camera views.
|
|
36209
36276
|
|
|
36210
36277
|
CAMERA SCENES:
|
|
36211
36278
|
{scenes}
|
|
36212
36279
|
|
|
36213
|
-
|
|
36214
|
-
|
|
36215
|
-
|
|
36216
|
-
|
|
36280
|
+
## PRIORITY ORDER (most important first):
|
|
36281
|
+
|
|
36282
|
+
### 1. SHARED LANDMARKS (HIGHEST PRIORITY)
|
|
36283
|
+
Identify features that are visible from MULTIPLE cameras. This is crucial for understanding the property layout.
|
|
36284
|
+
- Look for the SAME fence, tree, mailbox, driveway, structure, etc. appearing in different camera views
|
|
36285
|
+
- Even partial visibility counts (e.g., a tree visible in full from one camera and just the edge from another)
|
|
36286
|
+
- Include landmarks that are at the boundary between camera views
|
|
36287
|
+
|
|
36288
|
+
### 2. PROPERTY LAYOUT
|
|
36289
|
+
Based on what each camera sees and their overlapping features, describe:
|
|
36290
|
+
- Which areas each camera covers
|
|
36291
|
+
- How the cameras relate spatially (e.g., "Camera A looks toward Camera B's direction")
|
|
36292
|
+
- Overall property shape and features
|
|
36293
|
+
|
|
36294
|
+
### 3. CONNECTIONS (Lower Priority)
|
|
36295
|
+
Only if clearly determinable, suggest walking paths between camera views.
|
|
36217
36296
|
|
|
36218
36297
|
IMPORTANT: For camera references, use the EXACT device ID shown in parentheses (e.g., "device_123"), NOT the camera name.
|
|
36219
36298
|
|
|
36220
36299
|
Respond with ONLY valid JSON:
|
|
36221
36300
|
{
|
|
36222
36301
|
"sharedLandmarks": [
|
|
36223
|
-
{"name": "
|
|
36302
|
+
{"name": "Aluminum Fence", "type": "boundary", "seenByCameras": ["device_123", "device_456"], "confidence": 0.85, "description": "Silver aluminum fence visible on right edge of Camera A and left edge of Camera B"},
|
|
36303
|
+
{"name": "Large Oak Tree", "type": "feature", "seenByCameras": ["device_123", "device_789"], "confidence": 0.9, "description": "Mature oak tree in front yard, visible from both front and side cameras"},
|
|
36304
|
+
{"name": "Concrete Driveway", "type": "access", "seenByCameras": ["device_123", "device_456", "device_789"], "confidence": 0.95, "description": "Driveway visible from multiple angles"}
|
|
36224
36305
|
],
|
|
36225
36306
|
"connections": [
|
|
36226
|
-
{"from": "device_123", "to": "device_456", "transitSeconds":
|
|
36307
|
+
{"from": "device_123", "to": "device_456", "transitSeconds": 8, "via": "along driveway", "confidence": 0.6, "bidirectional": true}
|
|
36227
36308
|
],
|
|
36228
|
-
"layoutDescription": "
|
|
36309
|
+
"layoutDescription": "Ranch-style house. Front camera covers front yard and street. Garage camera covers driveway entrance. Side camera covers side yard with aluminum fence separating from neighbor. Backyard camera shows deck and pool area."
|
|
36229
36310
|
}`;
|
|
36230
36311
|
class TopologyDiscoveryEngine {
|
|
36231
36312
|
config;
|
|
@@ -36411,7 +36492,7 @@ class TopologyDiscoveryEngine {
|
|
|
36411
36492
|
],
|
|
36412
36493
|
},
|
|
36413
36494
|
],
|
|
36414
|
-
max_tokens:
|
|
36495
|
+
max_tokens: 4000, // Increased for detailed scene analysis
|
|
36415
36496
|
temperature: 0.3,
|
|
36416
36497
|
});
|
|
36417
36498
|
const content = result?.choices?.[0]?.message?.content;
|
|
@@ -36422,13 +36503,15 @@ class TopologyDiscoveryEngine {
|
|
|
36422
36503
|
if (jsonStr.startsWith('```')) {
|
|
36423
36504
|
jsonStr = jsonStr.replace(/```json?\n?/g, '').replace(/```$/g, '').trim();
|
|
36424
36505
|
}
|
|
36425
|
-
|
|
36506
|
+
// Try to recover truncated JSON
|
|
36507
|
+
const parsed = this.parseJsonWithRecovery(jsonStr, cameraName);
|
|
36426
36508
|
// Map parsed data to our types
|
|
36427
36509
|
if (Array.isArray(parsed.landmarks)) {
|
|
36428
36510
|
analysis.landmarks = parsed.landmarks.map((l) => ({
|
|
36429
36511
|
name: l.name || 'Unknown',
|
|
36430
36512
|
type: this.mapLandmarkType(l.type),
|
|
36431
36513
|
confidence: typeof l.confidence === 'number' ? l.confidence : 0.7,
|
|
36514
|
+
distance: this.mapDistance(l.distance),
|
|
36432
36515
|
description: l.description || '',
|
|
36433
36516
|
boundingBox: l.boundingBox,
|
|
36434
36517
|
}));
|
|
@@ -36546,6 +36629,108 @@ class TopologyDiscoveryEngine {
|
|
|
36546
36629
|
return 'west';
|
|
36547
36630
|
return 'unknown';
|
|
36548
36631
|
}
|
|
36632
|
+
/** Map LLM distance to our type */
|
|
36633
|
+
mapDistance(distance) {
|
|
36634
|
+
const dist = distance?.toLowerCase();
|
|
36635
|
+
if (dist?.includes('close'))
|
|
36636
|
+
return 'close';
|
|
36637
|
+
if (dist?.includes('near'))
|
|
36638
|
+
return 'near';
|
|
36639
|
+
if (dist?.includes('medium'))
|
|
36640
|
+
return 'medium';
|
|
36641
|
+
if (dist?.includes('far') && !dist?.includes('distant'))
|
|
36642
|
+
return 'far';
|
|
36643
|
+
if (dist?.includes('distant'))
|
|
36644
|
+
return 'distant';
|
|
36645
|
+
return 'medium'; // Default to medium if not specified
|
|
36646
|
+
}
|
|
36647
|
+
/** Try to parse JSON with recovery for truncated responses */
|
|
36648
|
+
parseJsonWithRecovery(jsonStr, context) {
|
|
36649
|
+
// First, try direct parse
|
|
36650
|
+
try {
|
|
36651
|
+
return JSON.parse(jsonStr);
|
|
36652
|
+
}
|
|
36653
|
+
catch (e) {
|
|
36654
|
+
// Log the raw response for debugging (first 500 chars)
|
|
36655
|
+
this.console.log(`[Discovery] Raw LLM response for ${context} (first 500 chars): ${jsonStr.substring(0, 500)}...`);
|
|
36656
|
+
}
|
|
36657
|
+
// Try to recover truncated JSON by finding complete sections
|
|
36658
|
+
try {
|
|
36659
|
+
// Find where valid JSON might end (look for last complete object/array)
|
|
36660
|
+
let recoveredJson = jsonStr;
|
|
36661
|
+
// Try to close unclosed strings
|
|
36662
|
+
const lastQuote = recoveredJson.lastIndexOf('"');
|
|
36663
|
+
const lastColon = recoveredJson.lastIndexOf(':');
|
|
36664
|
+
if (lastQuote > lastColon) {
|
|
36665
|
+
// We might be in the middle of a string value
|
|
36666
|
+
const beforeQuote = recoveredJson.substring(0, lastQuote);
|
|
36667
|
+
const afterLastCompleteEntry = beforeQuote.lastIndexOf('},');
|
|
36668
|
+
if (afterLastCompleteEntry > 0) {
|
|
36669
|
+
recoveredJson = beforeQuote.substring(0, afterLastCompleteEntry + 1);
|
|
36670
|
+
}
|
|
36671
|
+
}
|
|
36672
|
+
// Close any unclosed arrays/objects
|
|
36673
|
+
let openBraces = (recoveredJson.match(/{/g) || []).length;
|
|
36674
|
+
let closeBraces = (recoveredJson.match(/}/g) || []).length;
|
|
36675
|
+
let openBrackets = (recoveredJson.match(/\[/g) || []).length;
|
|
36676
|
+
let closeBrackets = (recoveredJson.match(/\]/g) || []).length;
|
|
36677
|
+
// Add missing closing brackets/braces
|
|
36678
|
+
while (closeBrackets < openBrackets) {
|
|
36679
|
+
recoveredJson += ']';
|
|
36680
|
+
closeBrackets++;
|
|
36681
|
+
}
|
|
36682
|
+
while (closeBraces < openBraces) {
|
|
36683
|
+
recoveredJson += '}';
|
|
36684
|
+
closeBraces++;
|
|
36685
|
+
}
|
|
36686
|
+
const recovered = JSON.parse(recoveredJson);
|
|
36687
|
+
this.console.log(`[Discovery] Recovered truncated JSON for ${context}`);
|
|
36688
|
+
return recovered;
|
|
36689
|
+
}
|
|
36690
|
+
catch (recoveryError) {
|
|
36691
|
+
// Last resort: try to extract just landmarks array
|
|
36692
|
+
try {
|
|
36693
|
+
const landmarksMatch = jsonStr.match(/"landmarks"\s*:\s*\[([\s\S]*?)(?:\]|$)/);
|
|
36694
|
+
const zonesMatch = jsonStr.match(/"zones"\s*:\s*\[([\s\S]*?)(?:\]|$)/);
|
|
36695
|
+
const result = { landmarks: [], zones: [], edges: {}, orientation: 'unknown' };
|
|
36696
|
+
if (landmarksMatch) {
|
|
36697
|
+
// Try to parse individual landmark objects
|
|
36698
|
+
const landmarksStr = landmarksMatch[1];
|
|
36699
|
+
const landmarkObjects = landmarksStr.match(/\{[^{}]*\}/g) || [];
|
|
36700
|
+
result.landmarks = landmarkObjects.map((obj) => {
|
|
36701
|
+
try {
|
|
36702
|
+
return JSON.parse(obj);
|
|
36703
|
+
}
|
|
36704
|
+
catch {
|
|
36705
|
+
return null;
|
|
36706
|
+
}
|
|
36707
|
+
}).filter(Boolean);
|
|
36708
|
+
this.console.log(`[Discovery] Extracted ${result.landmarks.length} landmarks from partial response for ${context}`);
|
|
36709
|
+
}
|
|
36710
|
+
if (zonesMatch) {
|
|
36711
|
+
const zonesStr = zonesMatch[1];
|
|
36712
|
+
const zoneObjects = zonesStr.match(/\{[^{}]*\}/g) || [];
|
|
36713
|
+
result.zones = zoneObjects.map((obj) => {
|
|
36714
|
+
try {
|
|
36715
|
+
return JSON.parse(obj);
|
|
36716
|
+
}
|
|
36717
|
+
catch {
|
|
36718
|
+
return null;
|
|
36719
|
+
}
|
|
36720
|
+
}).filter(Boolean);
|
|
36721
|
+
this.console.log(`[Discovery] Extracted ${result.zones.length} zones from partial response for ${context}`);
|
|
36722
|
+
}
|
|
36723
|
+
if (result.landmarks.length > 0 || result.zones.length > 0) {
|
|
36724
|
+
return result;
|
|
36725
|
+
}
|
|
36726
|
+
}
|
|
36727
|
+
catch (extractError) {
|
|
36728
|
+
// Give up
|
|
36729
|
+
}
|
|
36730
|
+
this.console.warn(`[Discovery] Could not recover JSON for ${context}`);
|
|
36731
|
+
throw new Error(`Failed to parse LLM response: truncated or malformed JSON`);
|
|
36732
|
+
}
|
|
36733
|
+
}
|
|
36549
36734
|
/** Resolve a camera reference (name or deviceId) to its deviceId */
|
|
36550
36735
|
resolveCameraRef(ref) {
|
|
36551
36736
|
if (!this.topology?.cameras || !ref)
|
|
@@ -36721,9 +36906,12 @@ class TopologyDiscoveryEngine {
|
|
|
36721
36906
|
generateSuggestionsFromAnalysis(analysis) {
|
|
36722
36907
|
if (!analysis.isValid)
|
|
36723
36908
|
return;
|
|
36909
|
+
this.console.log(`[Discovery] Generating suggestions from ${analysis.landmarks.length} landmarks, ${analysis.zones.length} zones`);
|
|
36724
36910
|
// Generate landmark suggestions
|
|
36725
36911
|
for (const landmark of analysis.landmarks) {
|
|
36726
36912
|
if (landmark.confidence >= this.config.minLandmarkConfidence) {
|
|
36913
|
+
// Calculate distance in feet from distance estimate
|
|
36914
|
+
const distanceFeet = landmark.distance ? (0, discovery_1.distanceToFeet)(landmark.distance) : 50;
|
|
36727
36915
|
const suggestion = {
|
|
36728
36916
|
id: `landmark_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
36729
36917
|
type: 'landmark',
|
|
@@ -36736,26 +36924,30 @@ class TopologyDiscoveryEngine {
|
|
|
36736
36924
|
type: landmark.type,
|
|
36737
36925
|
description: landmark.description,
|
|
36738
36926
|
visibleFromCameras: [analysis.cameraId],
|
|
36739
|
-
// Include
|
|
36927
|
+
// Include extra metadata for positioning
|
|
36740
36928
|
boundingBox: landmark.boundingBox,
|
|
36741
|
-
|
|
36929
|
+
distance: landmark.distance,
|
|
36930
|
+
distanceFeet: distanceFeet,
|
|
36931
|
+
}, // Extra metadata not in base Landmark interface
|
|
36742
36932
|
};
|
|
36743
36933
|
this.suggestions.set(suggestion.id, suggestion);
|
|
36934
|
+
this.console.log(`[Discovery] Landmark suggestion: ${landmark.name} (${landmark.type}, ${landmark.distance || 'medium'}, ~${distanceFeet}ft)`);
|
|
36744
36935
|
}
|
|
36745
36936
|
}
|
|
36746
|
-
// Generate zone suggestions
|
|
36937
|
+
// Generate zone suggestions (even for smaller coverage - 10% is enough)
|
|
36747
36938
|
for (const zone of analysis.zones) {
|
|
36748
|
-
if (zone.coverage >= 0.
|
|
36939
|
+
if (zone.coverage >= 0.1) {
|
|
36749
36940
|
const suggestion = {
|
|
36750
36941
|
id: `zone_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
36751
36942
|
type: 'zone',
|
|
36752
36943
|
timestamp: Date.now(),
|
|
36753
36944
|
sourceCameras: [analysis.cameraId],
|
|
36754
|
-
confidence: 0.
|
|
36945
|
+
confidence: Math.min(0.9, 0.5 + zone.coverage), // Higher coverage = higher confidence
|
|
36755
36946
|
status: 'pending',
|
|
36756
36947
|
zone: zone,
|
|
36757
36948
|
};
|
|
36758
36949
|
this.suggestions.set(suggestion.id, suggestion);
|
|
36950
|
+
this.console.log(`[Discovery] Zone suggestion: ${zone.name} (${zone.type}, ${Math.round(zone.coverage * 100)}% coverage)`);
|
|
36759
36951
|
}
|
|
36760
36952
|
}
|
|
36761
36953
|
}
|
|
@@ -41157,6 +41349,7 @@ function createAlert(type, trackedObjectId, details, severity = 'info', ruleId)
|
|
|
41157
41349
|
*/
|
|
41158
41350
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
41159
41351
|
exports.DEFAULT_DISCOVERY_STATUS = exports.RATE_LIMIT_WARNING_THRESHOLD = exports.DEFAULT_DISCOVERY_CONFIG = void 0;
|
|
41352
|
+
exports.distanceToFeet = distanceToFeet;
|
|
41160
41353
|
/** Default discovery configuration */
|
|
41161
41354
|
exports.DEFAULT_DISCOVERY_CONFIG = {
|
|
41162
41355
|
discoveryIntervalHours: 0, // Disabled by default
|
|
@@ -41166,6 +41359,17 @@ exports.DEFAULT_DISCOVERY_CONFIG = {
|
|
|
41166
41359
|
};
|
|
41167
41360
|
/** Rate limit warning thresholds (in hours) */
|
|
41168
41361
|
exports.RATE_LIMIT_WARNING_THRESHOLD = 1; // Warn if interval is less than 1 hour
|
|
41362
|
+
/** Convert distance estimate to approximate feet */
|
|
41363
|
+
function distanceToFeet(distance) {
|
|
41364
|
+
switch (distance) {
|
|
41365
|
+
case 'close': return 5; // 0-10 feet
|
|
41366
|
+
case 'near': return 20; // 10-30 feet
|
|
41367
|
+
case 'medium': return 45; // 30-60 feet
|
|
41368
|
+
case 'far': return 80; // 60-100 feet
|
|
41369
|
+
case 'distant': return 150; // 100+ feet
|
|
41370
|
+
default: return 50;
|
|
41371
|
+
}
|
|
41372
|
+
}
|
|
41169
41373
|
/** Default discovery status */
|
|
41170
41374
|
exports.DEFAULT_DISCOVERY_STATUS = {
|
|
41171
41375
|
isRunning: false,
|