Check macOS Spotlight semantic indexing readiness A developer published a JXA script that queries macOS Spotlight's CoreSpotlight indexing pipeline to report semantic search readiness, exposing the same XPC request used by CSSearchableIndex's fetchIndexingPipelineOverallCompleteness. The tool connects to the com.apple.spotlight.IndexAgent Mach service and decodes the CSIndexingPipelineOverallCompleteness report, printing overall completeness, donation and pipeline percentages, the sufficiency threshold, and report age. | | // Spotlight semantic search readiness, as reported by CoreSpotlight. | | | // Usage: osascript -l JavaScript readiness.js pipeline default: Embedding | | | // Or paste into Script Editor and pick JavaScript instead of AppleScript language | | | ObjC.import 'CoreSpotlight' ; | | | const bind = name, signature = ObjC.bindFunction name, signature ; | | | bind 'xpc connection create mach service', 'pointer', 'char ', 'pointer', 'unsigned long long' ; | | | bind 'xpc connection set event handler', 'void', 'pointer', 'id' ; | | | bind 'xpc connection resume', 'void', 'pointer' ; | | | bind 'xpc connection send message with reply sync', 'pointer', 'pointer', 'pointer' ; | | | bind 'xpc dictionary create', 'pointer', 'pointer', 'pointer', 'unsigned long' ; | | | bind 'xpc dictionary set string', 'void', 'pointer', 'char ', 'char ' ; | | | bind 'xpc dictionary set uint64', 'void', 'pointer', 'char ', 'unsigned long long' ; | | | bind 'xpc dictionary get data', 'pointer', 'pointer', 'char ', 'pointer' ; | | | bind 'xpc dictionary get uint64', 'unsigned long long', 'pointer', 'char ' ; | | | bind 'xpc dictionary get int64', 'long long', 'pointer', 'char ' ; | | | function run argv { | | | const pipeline = argv 0 \|\| 'Embedding'; | | | // Same request - CSSearchableIndex fetchIndexingPipelineOverallCompleteness:completionHandler: sends | | | const connection = $.xpc connection create mach service 'com.apple.spotlight.IndexAgent', null, 0 ; | | | $.xpc connection set event handler connection, ObjC.block 'void', 'pointer' , = {} ; | | | $.xpc connection resume connection ; | | | const request = $.xpc dictionary create null, null, 0 ; | | | $.xpc dictionary set uint64 request, 'id', 1 ; | | | $.xpc dictionary set string request, 'command', 'fetch-indexing-pipeline-completeness' ; | | | $.xpc dictionary set string request, 'command-type', 'index-type' ; | | | $.xpc dictionary set string request, 'n', 'CSSearchableIndexShared' ; | | | $.xpc dictionary set uint64 request, 'iopt', 0 ; | | | $.xpc dictionary set string request, 'indexing-pipeline', pipeline ; | | | const reply = $.xpc connection send message with reply sync connection, request ; | | | // Nonzero status: unknown pipeline, or no report yet first minutes after install | | | if Number $.xpc dictionary get int64 reply, 'status' == 0 return No report for ${pipeline} ; | | | const size = $.xpc dictionary get uint64 reply, 'indexing-pipeline-completeness-size' ; | | | const bytes = $.xpc dictionary get data reply, 'indexing-pipeline-completeness', null ; | | | const report = $.NSKeyedUnarchiver.unarchivedObjectOfClassFromDataError | | | $.NSClassFromString 'CSIndexingPipelineOverallCompleteness' , $.NSData.dataWithBytesLength bytes, size , null ; | | | const value = key = ObjC.unwrap report.valueForKey key ; | | | const percent = key = value key == null ? 'n/a' : value key 100 .toFixed 1 + '%'; | | | const status = value 'isSufficientlyComplete' ? 'Ready' : 'Still processing'; | | | return | | | Search readiness: ${percent 'overallCompleteness' } — ${status} ${percent 'sufficientlyCompleteThreshold' } required , | | | Known app items donated: ${percent 'donationCompeleteness' } , | | | Search pipeline processed: ${percent 'pipelineCompleteness' } , | | | Report age: ${ value 'pipelineReportAge' / 3600 .toFixed 1 } hours , | | | .join '\n' ; | | | } |