{"id":13549246,"url":"https://github.com/techouse/alfred_workflow","last_synced_at":"2025-04-13T12:28:45.384Z","repository":{"id":56825911,"uuid":"466748148","full_name":"techouse/alfred_workflow","owner":"techouse","description":"A helper library in Dart for authors of workflows for Alfred","archived":false,"fork":false,"pushed_at":"2025-04-06T17:29:19.000Z","size":630,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-13T12:28:29.743Z","etag":null,"topics":["alfred","alfred-workflow","dart","workflow"],"latest_commit_sha":null,"homepage":"https://techouse.github.io/alfred_workflow/","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/techouse.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"techouse","custom":["https://paypal.me/ktusar"]}},"created_at":"2022-03-06T13:38:34.000Z","updated_at":"2025-04-06T17:26:47.000Z","dependencies_parsed_at":"2023-02-18T16:31:07.003Z","dependency_job_id":"5a53bdb3-10ca-4203-bbd7-d966523baefc","html_url":"https://github.com/techouse/alfred_workflow","commit_stats":{"total_commits":146,"total_committers":2,"mean_commits":73.0,"dds":"0.020547945205479423","last_synced_commit":"afbc639804865b4afa67deb1f23488cf640a0df6"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techouse%2Falfred_workflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techouse%2Falfred_workflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techouse%2Falfred_workflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/techouse%2Falfred_workflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/techouse","download_url":"https://codeload.github.com/techouse/alfred_workflow/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248713717,"owners_count":21149752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alfred","alfred-workflow","dart","workflow"],"created_at":"2024-08-01T12:01:19.817Z","updated_at":"2025-04-13T12:28:45.376Z","avatar_url":"https://github.com/techouse.png","language":"Dart","funding_links":["https://github.com/sponsors/techouse","https://paypal.me/ktusar"],"categories":["Dart","Helpers"],"sub_categories":[],"readme":"# Alfred Workflow\n\nA helper library in Dart for authors of workflows for [Alfred](https://www.alfredapp.com).\n\n[![Pub Version](https://img.shields.io/pub/v/alfred_workflow)](https://pub.dev/packages/alfred_workflow)\n[![Pub Publisher](https://img.shields.io/pub/publisher/alfred_workflow)](https://pub.dev/publishers/tusar.dev/packages)\n[![Pub Likes](https://img.shields.io/pub/likes/alfred_workflow)](https://pub.dev/packages/alfred_workflow/score)\n[![Pub Points](https://img.shields.io/pub/points/alfred_workflow)](https://pub.dev/packages/alfred_workflow/score)\n[![Pub Popularity](https://img.shields.io/pub/popularity/alfred_workflow)](https://pub.dev/packages/alfred_workflow/score)\n[![Dart CI](https://github.com/techouse/alfred_workflow/actions/workflows/test.yml/badge.svg)](https://github.com/techouse/alfred_workflow/actions/workflows/test.yml)\n[![codecov](https://codecov.io/gh/techouse/alfred_workflow/branch/master/graph/badge.svg?token=SkypLLzvM3)](https://codecov.io/gh/techouse/alfred_workflow)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/8f4453a193c94f6eb4239f95718d1cea)](https://www.codacy.com/gh/techouse/alfred_workflow/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=techouse/alfred_workflow\u0026amp;utm_campaign=Badge_Grade)\n[![GitHub](https://img.shields.io/github/license/techouse/alfred_workflow)](LICENSE)\n[![GitHub Sponsors](https://img.shields.io/github/sponsors/techouse)](https://github.com/sponsors/techouse)\n[![GitHub Repo stars](https://img.shields.io/github/stars/techouse/alfred_workflow)](https://github.com/techouse/alfred_workflow/stargazers)\n\nThis library is heavily inspired by the excellent Python library [deanishe/alfred-workflow](https://github.com/deanishe/alfred-workflow).\n\n## 🚸 Usage\n\n### 🎉 Basic example\n\n```dart\nimport 'dart:io' show exitCode;\n\nimport 'package:alfred_workflow/alfred_workflow.dart';\nimport 'package:args/args.dart';\nimport 'package:cli_script/cli_script.dart';\n\nvoid main(List\u003cString\u003e arguments) {\n  /// It's recommended that all scripts wrap their main() methods in wrapMain.\n  /// It gracefully exits when an error is unhandled, and (if chainStackTraces is true) \n  /// tracks stack traces across asynchronous calls to produce better error stacks.\n  wrapMain(() async {\n    /// Instantiate an AlfredWorkflow\n    final workflow = AlfredWorkflow();\n\n    try {\n      exitCode = 0;\n\n      /// Define an ArgParser that uses -q/--query to listen to search queries\n      final ArgParser parser = ArgParser()\n        ..addOption('query', abbr: 'q', defaultsTo: '');\n\n      /// Parse the args\n      final ArgResults args = parser.parse(arguments);\n\n      /// Sanitize the query string obtained from the args\n      final String query = args['query'].replaceAll(RegExp(r'\\s+'), ' ').trim();\n\n      if (query.isEmpty) {\n        /// In case of an empty query display a placeholder in the Alfred feedback\n        workflow.addItem(\n          const AlfredItem(\n            title: 'Search for some particular stuff ...',\n            icon: AlfredItemIcon(path: 'icon.png'),\n          ),\n        );\n      } else {\n        /// When there is a query do something fancy\n\n        /// In this case we'll search Google with our query.\n        final Uri url = Uri.https('www.google.com', '/search', {'q': query});\n\n        /// Add an item to the Alfred feedback\n        workflow.addItem(\n          AlfredItem(\n            title: 'Sorry I can\\'t help you with that query.',\n            subtitle: 'Shall I try and search Google?',\n            arg: url.toString(),\n            text: AlfredItemText(\n              copy: url.toString(),\n            ),\n            quickLookUrl: url.toString(),\n            icon: AlfredItemIcon(path: 'google.png'),\n            valid: true,\n          ),\n        );\n      }\n    } catch (err) {\n      /// Set exit code to a non-zero number\n      exitCode = 1;\n\n      /// In case of errors you can simply output the message in the Alfred feedback\n      workflow.addItem(\n        AlfredItem(title: err.toString()),\n      );\n    } finally {\n      /// This will always print JSON to the stdout and send that to Alfred.\n      workflow.run();\n    }\n  });\n}\n```\n\nTo search for the string \"hello\" simply execute this on the commandline:\n\n```bash\ndart run example.dart --query 'hello'\n```\n\nCheck out the [basic example here](example/alfred_workflow_example.dart).\n\n### ⚡️ Speed it up using caching\n\nThe library uses [stash_file](https://pub.dev/packages/stash_file) to cache results in the form of `AlfredItems`.\nAll you need to do to enable it is to define a `cacheKey`.\n\n```dart\n/// Define a cacheKey. In this case you can just use the query.\nworkflow.cacheKey = query;\n\n/// Check if anything using that cacheKey is already in the cache.\n/// This will automatically add the cached items to the Alfred feedback.\nfinal AlfredItems? cachedItems = await workflow.getItems();\n\n/// If noting was cached simply do as before\nif (cachedItems == null) {\n  final Uri url = Uri.https('www.google.com', '/search', {'q': query});\n\n  /// This will now automatically add the AlfredItem to the cache.\n  workflow.addItem(\n    AlfredItem(\n      title: 'Sorry I can\\'t help you with that query.',\n      subtitle: 'Shall I try and search Google?',\n      arg: url.toString(),\n      text: AlfredItemText(\n        copy: url.toString(),\n      ),\n      quickLookUrl: url.toString(),\n      icon: AlfredItemIcon(path: 'google.png'),\n      valid: true,\n    ),\n  );\n}\n```\n\nCheck out the [caching example here](example/alfred_workflow_caching_example.dart).\n\n### 🔧 Workflow Configuration\n\nThis library supports new [Workflow Configuration](https://www.alfredapp.com/help/workflows/workflow-configuration/) added in Alfred 5.\n\n\u003e Workflow Configuration defaults are stored in `info.plist`, but changed values are saved to `prefs.plist`.\n\u003e Add the latter to your `.gitignore` to not commit your personal configuration to version control.\n\nYou can access the user defaults like this:\n\n```dart\nfinal Map\u003cString, AlfredUserConfiguration\u003e? userDefaults = await workflow.getUserDefaults();\n```\n\nThis will return a `Map` of `AlfredUserConfiguration` objects keyed by the `key` you defined in your `info.plist`.\n\n```dart\n// this example uses a select configuration\nfinal AlfredUserConfigurationSelect? currencyConfiguration = userDefaults?['currency'];\n```\n\nYou can then access the user set (or default) `value` of the `AlfredUserConfiguration` object.\n\n```dart\nfinal String? defaultCurrency = currencyConfiguration?.defaultValue;\nfinal String? userCurrency = currencyConfiguration?.value;\n```\n\n### ⬆️ Auto-Update your workflows via GitHub releases\n\nSetting up Auto-Updating will require that you provide your workflow's Github repository URL and version.\nOptionally you can set an interval how frequently the workflow should check for updates.\n\nOnce an update is found it's downloaded to the temp and opened.\n\n```dart\nfinal AlfredUpdater updater = AlfredUpdater(\n  /// Declare your workflow's Github repository URL\n  githubRepositoryUrl: Uri.parse('https://github.com/your/repo'),\n  /// Declare your workflow's current working version\n  currentVersion: '1.0.0',\n  /// Optionally set an interval how frequently it should check for updates\n  updateInterval: Duration(days: 7),\n);\n\n/// Check for updates\nif (await updater.updateAvailable()) {\n  /// Run the update\n  await updater.update();\n}\n```\n\nTo update the workflow simply run this from the commandline:\n\n```bash\ndart run example.dart --update\n```\n\nCheck out the [auto-update example here](example/alfred_workflow_auto_update_example.dart).\n\n## 🚀 Building the workflow for production\n\nDart scripts can be [easily compiled to standalone executables](https://dart.dev/tools/dart-compile) eliminating the need for any external prerequisites.\n\nTo compile the script above simply run this from the commandline:\n\n```bash\ndart compile exe example.dart --output example\n```\n\nYou can then invoke the executable from the commandline:\n\n```bash\n./example --query 'hello'\n```\n\n### 📄 Signing and notarizing the compiled binary before distribution\n\n[Signing on macOS](https://dart.dev/tools/dart-compile#signing) became available with [Dart 2.17](https://dart.dev/guides/whats-new#may-11-2022-217-release).\n\nIf you want to distribute your compiled Mach-O binary you should **sign** and **notarize** it with Apple.\n\nUse the bash script below as a template to help you with this process.\n\n```bash\n#!/usr/bin/env bash\n\n# This script should be a starting point to help you sign and notarise a Mach-O binary app.\n# Read it carefully and replace any placeholders with actual data.\n\n# Sign the compiled binary\ncodesign \\\n  --sign=\"XXXX\" \\                        # replace with hash of \"Developer ID Application: Your name (Your Team)\"\n  --identifier=\"com.example.test\" \\      # replace with app's bundle id\n  --deep \\\n  --force \\\n  --options=runtime \\\n  --entitlement=\"./entitlements.plist\" \\ # must allow com.apple.security.cs.allow-unsigned-executable-memory\n  --timestamp \\\n  --verbose=4 \\\n  ./path/to/compiled/exe\n\n# Verify the signed binary\ncodesign -dv --verbose=4 ./path/to/compiled/exe\n\n# ZIP the binary because altool won't accept a raw Mach-O binary\nzip -j ./path/to/compiled/exe.zip ./path/to/compiled/exe\n\n# Notarize the binary in ZIP form\n# For more info refer to https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow#3087734\nxcrun notarytool \\\n  submit path/to/compiled/exe.zip \\\n  --keychain-profile \"notarytool-password\" \\  # replace with an app specific password https://support.apple.com/en-us/HT204397\n  --wait\n\n# Delete zip file as it's no longer needed at this point\n# Apple will notarize the Mach-O binary inside the ZIP\nrm ./path/to/compiled/exe.zip\n\n# Wait a while then verify your Mach-O binary\nspctl -a -vvv -t install ./path/to/compiled/exe\n\n# In case you encountered an error run and check the output\nxcrun altool \\\n  --notarization-info \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\" \\  # the UUID altool gave you\n  --username \"john.appleseed@apple.com\" \\                       # Apple ID username\n  --password \"@keychain:Developer-altool\"                       # same app-specific password\n```\n\nFore more info please refer to [the Apple Code Signing guide](https://developer.apple.com/support/code-signing/) as well \nas to [this exhaustive StackOverflow answer](https://stackoverflow.com/questions/64652704/how-to-notarize-an-macos-command-line-tool-created-outside-of-xcode#answer-64733472).\n\n## 🌱 A couple of my Alfred Workflows built using this library\n\n- [alfred-flutter-docs](https://github.com/techouse/alfred-flutter-docs)\n- [alfred-dart-docs](https://github.com/techouse/alfred-dart-docs)\n- [alfred-react-docs](https://github.com/techouse/alfred-react-docs)\n- [alfred-vue-docs](https://github.com/techouse/alfred-vue-docs)\n- [alfred-tailwindcss-docs](https://github.com/techouse/alfred-tailwindcss-docs)\n- [alfred-django-docs](https://github.com/techouse/alfred-django-docs)\n- [alfred-flask-docs](https://github.com/techouse/alfred-flask-docs)\n- [alfred-laravel-docs](https://github.com/techouse/alfred-laravel-docs)\n- [alfred-nova-docs](https://github.com/techouse/alfred-nova-docs)\n- [alfred-cakephp-docs](https://github.com/techouse/alfred-cakephp-docs)\n- [alfred-gitmoji](https://github.com/techouse/alfred-gitmoji)\n- [alfred-stackoverflow](https://github.com/techouse/alfred-stackoverflow)\n- [alfred-convert](https://github.com/techouse/alfred-convert)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechouse%2Falfred_workflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftechouse%2Falfred_workflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftechouse%2Falfred_workflow/lists"}