Created
September 24, 2026 00:59
-
-
Save pointum/22aaa925df98497a40a61d71f0d95a06 to your computer and use it in GitHub Desktop.
Check macOS Spotlight semantic indexing readiness
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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'); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment