Run encoded javascript to get task ID

I’m trying to use a keyboard maestro macro to invoke some java script to do some querying of omnifocus and produce a URL I want to get back to keyboard Maestro so I can save it there.

The use case is a simple script that takes a selection in OF and searches possible children looking for a specific tag, when the tag is found I want to get the task ID back to KM.

Closest I got is to us xcall.app through KM’s execute shell script which I can do but I can’t get the final piece together where I can get KM to store that task ID. I think I just need xcall.app, at minimum to just print to stdout so KM can capture that.

Any ideas?

A JavaScript for Automation action, I think.

You could get a list of task ids for a given tag name by writing code like this:

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    const
        omnifocus = Application("OmniFocus"),
        tagName = "Tutorial";

    return omnifocus.defaultDocument
        .tags.byName(tagName)
        .tasks
        .id()
		.join("\n")

})();
1 Like

Thanks! That does help showing me that I can return a list of task IDs to Keyboard Maestro which is kinda what I want but my starting point was to run some test code from the omniJS console but then later call it from Keyboard Maestro to get the results into a KM variable

The way to go about this seems elusive to me but I can run this from the omni console and get almost what I want I just don’t know how to “return the task ID” back to Keyboard Maestro

Here’s a script I’m trying to adapt to return what it finds to KM, I can run it from the omni automation console

var win = document.windows[0]
var tasks = win.selection.tasks
tasks.forEach(task => {
console.log("->", task.name)
console.log(“parent w/tags: “, task.tags)
var doneTag = flattenedTags.byName(“✅”)
if (task.hasChildren){
task.children.forEach(task => {
console.log(” -> “, task.name)
console.log(” kid w/tags: “, task.tags)
task.tags.forEach(tag => {
if (tag.name == “✅”){
console.log(“FOUND DONE”, task.tags)
console.log(” parent”, task.parent)
console.log(" ID of kid", task.id.primaryKey)
//open(“omnifocus:///task/hSXeRoGYJAg”)
}
}
)})}})

In the above with the selection I’m testing with I know I can get a task ID that I will want to save and use open URL from another macro later. But not sure how I can “return” the taskID to KM. I can percent encode this and run either

omnifocus:///omnijs-run?script=%omni JS encoded%

omnifocus://x-callback-url/omnijs-run?script=% omni JS encoded%

to invoke the script and have it do what I want.

I can also use xcallback.app from within KM

/Applications/xcall.app/Contents/MacOS/xcall -url "omnifocus://x-callback-url/omnijs-run?script=%omni JS encoded%

and save results from that but again I still can’t get the task ID to “be returned”

I tried to mess with setting and getting KM variables from within the code I send to OmniFocus but I can’t seem to use

var app = Application.currentApplication()
app.includeStandardAdditions = true
var kme = Application(“Keyboard Maestro Engine”);
var foundTaskID = “omnifocus:///task/” foundTaskID;
kme.setvariable(“task_to_open_later”, { to: foundTaskID });

but from what I can see the omniJS console doesn’t have “Application” so I can’t get that context to us the KM JXA API to get and set KM variables

Well, OK, but technical starting points tend to yield tangle.

The only simplifying starting point is the end goal.

JXA is designed for interaction with the whole system.

omniJS is more efficient for interacting with the Omni app itself, but its JS interpreter is embedded inside the app, and has very limited access to the rest of the system.

I’m not sure that omniJS is necessarily the right tool to reach for here.

A compromise (if you are more used to the omniJS interface) would be to launch the omniJS code, and harvest a result from it, using the JXA Application.evaluateJavascript method.

OmniJS code harvesting ID(s) to Keyboard Maestro through the JXA evaluateJavascript method:

Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    // ------------------- OMNIJS CODE -------------------

    // taskIDsFromTagName :: String -> [String]
    const taskIDsFromTagName = tagName => {
        const
            namedTag = flattenedTags.byName(
                tagName
            );

        return namedTag !== null ? (
            namedTag.tasks.map(
                task => task.id.primaryKey
            )
        ) : [];
    };

    // -------------------- JXA CODE ---------------------
    const main = () =>
        evalOmniJSWithArgs(
            "OmniFocus",
            taskIDsFromTagName,
            Application("Keyboard Maestro Engine")
            .getvariable("ofTagName")
        );


    // --------------------- GENERIC ---------------------

    // evalOmniJSWithArgs :: Function ->
    // [...OptionalArgs] -> a
    const evalOmniJSWithArgs = (appName, f, ...args) =>
        Application(appName).evaluateJavascript(
            `(${f})(${args.map(JSON.stringify)})`
        );

    return main();
})();
1 Like