shortcutkit 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 frontboat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # shortcutkit
2
+
3
+ Build, validate and sign Apple Shortcuts (`.shortcut`) files from TypeScript or Python.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+ [![CI](https://img.shields.io/github/actions/workflow/status/frontboat/shortcutkit/ci.yml?branch=main)](https://github.com/frontboat/shortcutkit/actions)
7
+
8
+ ## About
9
+
10
+ Shortcuts has no public file-format specification and no public list of what its actions
11
+ accept. shortcutkit fills that gap by extracting the action definitions and value encodings
12
+ from WorkflowKit, the engine inside the Shortcuts app, and generating a typed catalogue from
13
+ them. Every one of the 339 built-in actions is available with its parameter keys and value
14
+ shapes checked at compile time in TypeScript, or at run time in Python. Nothing was
15
+ transcribed by hand, and `data/provenance.json` records exactly which macOS and Shortcuts build
16
+ the data came from.
17
+
18
+ ## Features
19
+
20
+ - **Every built-in action, typed.** `actions.*` lists all 339 identifiers, with each action's
21
+ name, description, summary, output and parameter keys as hover documentation.
22
+ - **Parameters checked before you run anything.** `{ WFStoredContentGlobalValue: "yes" }` is a
23
+ compile error; a switch takes a boolean or a reference. Enumeration choices are suggested.
24
+ Any plain value slot also accepts an attachment, because that is how Shortcuts works.
25
+ - **Value helpers that match the engine's serialization.** `ref()` to another action's output,
26
+ `variable()`, `shortcutInput()`, `clipboard()`, `currentDate()`, `ask()`, `text()` for
27
+ strings with embedded references, and `picker()` for variable-picker parameters.
28
+ - **Control flow.** `if()` / `otherwise()` / `endIf()` and `repeatEach()` / `endRepeatEach()`
29
+ manage the grouping identifiers for you.
30
+ - **App Intents from installed apps.** Any identifier outside the built-in set is accepted;
31
+ built-in identifiers and their parameter keys are also validated at run time.
32
+ - **Definitions and provenance.** `getDefinition(id)` returns the full record (icon, keywords,
33
+ parameter classes, required resources); `provenance` says which build produced the data.
34
+ - **Signing.** `Shortcut.sign()` wraps `shortcuts sign` so the output imports on any device.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install shortcutkit # or: bun add shortcutkit
40
+ ```
41
+
42
+ Python:
43
+
44
+ ```bash
45
+ pip install shortcutkit
46
+ ```
47
+
48
+ ### Requirements
49
+
50
+ - Node 20 or newer, or Bun, for the TypeScript package. The published package is plain ES
51
+ module JavaScript with type declarations. Python 3.9 or newer for the Python package.
52
+ - A Mac signed into iCloud for `sign()`. It runs `shortcuts sign`, which refuses to work
53
+ without an iCloud login even in `anyone` mode, so it cannot run on CI runners. `write()`
54
+ converts the plist to binary with `plutil` when present and otherwise leaves the XML form.
55
+ Building, validating and writing the unsigned file works anywhere.
56
+
57
+ ## Usage
58
+
59
+ ```ts
60
+ import { Shortcut, actions, ref, text } from "shortcutkit";
61
+
62
+ const s = new Shortcut("Greeting", { color: "Teal" });
63
+ const got = s.action(actions.getstoredcontent, { WFStoredContentKey: "greeting" });
64
+ s.action(actions.showresult, { Text: text("Stored: ", ref(got)) });
65
+ await s.write(); // Greeting.shortcut
66
+ Shortcut.sign("Greeting.shortcut", "Greeting-signed.shortcut");
67
+ ```
68
+
69
+ Open the signed file and Shortcuts imports it.
70
+
71
+ ### Control flow
72
+
73
+ `if()` returns a grouping identifier that the matching `otherwise()` and `endIf()` calls take
74
+ back:
75
+
76
+ ```ts
77
+ const gid = s.if(ref(got), "has_any_value");
78
+ s.action(actions.showresult, { Text: text("Stored value: ", ref(got)) });
79
+ s.otherwise(gid);
80
+ s.action(actions.showresult, { Text: text("Nothing stored") });
81
+ s.endIf(gid);
82
+ ```
83
+
84
+ ### Actions from other apps
85
+
86
+ App Intents actions are not in the catalogue, so pass the identifier as a string. Parameter
87
+ keys are then typed as `Record<string, Value>` and passed through as given:
88
+
89
+ ```ts
90
+ s.action("com.example.app.CreateNote", { title: text("Hello"), body: ref(got) });
91
+ ```
92
+
93
+ ### Python
94
+
95
+ Same API and same bundled data, with snake_case names and run-time value checks instead of
96
+ compile-time ones:
97
+
98
+ ```python
99
+ from shortcutkit import Shortcut, actions, ref, text
100
+
101
+ s = Shortcut("Greeting", color="Teal")
102
+ got = s.action(actions.GETSTOREDCONTENT, WFStoredContentKey="greeting")
103
+ s.action(actions.SHOWRESULT, Text=text("Stored: ", ref(got)))
104
+ s.write()
105
+ Shortcut.sign("Greeting.shortcut", "Greeting-signed.shortcut")
106
+ ```
107
+
108
+ See [`python/README.md`](python/README.md) for the full Python surface.
109
+
110
+ ### Demo
111
+
112
+ Both packages ship a demo that builds a working shortcut with storage, an If/Otherwise block
113
+ and output:
114
+
115
+ ```bash
116
+ bun run demo out.shortcut
117
+ python -m shortcutkit demo out.shortcut
118
+ ```
119
+
120
+ ## Documentation
121
+
122
+ - [`docs/shortcut-file-format.md`](docs/shortcut-file-format.md): the `.shortcut` format end
123
+ to end, every field.
124
+ - [`docs/builtin-actions-reference.md`](docs/builtin-actions-reference.md): all 339 built-in
125
+ actions with their parameters.
126
+ - [`docs/parameter-encodings.md`](docs/parameter-encodings.md): how each parameter class is
127
+ serialized.
128
+ - [`docs/extraction.md`](docs/extraction.md): how the data was obtained, what did not work,
129
+ and what remains approximate. A handful of condition codes rest on community documentation.
130
+
131
+ ## Development
132
+
133
+ ```bash
134
+ git clone https://github.com/frontboat/shortcutkit.git && cd shortcutkit
135
+ bun install
136
+ bun test # all tests
137
+ bun run typecheck # tsc --noEmit; also verifies the @ts-expect-error assertions in tests
138
+ bun run build # bundles src/ into dist/index.js for Node and emits the .d.ts files
139
+
140
+ cd python && python3 -m venv .venv && .venv/bin/pip install -e .
141
+ .venv/bin/python -m shortcutkit demo /tmp/Demo.shortcut
142
+ ```
143
+
144
+ CI runs the type check, the tests, a Node import of the built package, a Python install and an
145
+ unsigned build of the demo shortcut on macOS. Signing is not exercised in CI because the runner
146
+ has no iCloud login.
147
+
148
+ ### Repository layout
149
+
150
+ | Path | Contents |
151
+ |---|---|
152
+ | `src/` | The TypeScript package source. `src/generated/actions.ts` is produced by the tools. `bun run build` bundles it into `dist/`, which is what npm ships. |
153
+ | `python/` | The Python package. `actions.py` and `data/` are produced by the tools. |
154
+ | `data/` | Everything extracted from the engine: definitions, parameter encodings, serialization table, and `provenance.json`. |
155
+ | `docs/` | The format reference, action reference, encodings reference and extraction notes. |
156
+ | `tools/` | The extraction pipeline. |
157
+
158
+ Never hand-edit the generated files. Change the generator or the data and re-run the pipeline.
159
+
160
+ ### Regenerating the data
161
+
162
+ The extracted data is committed on purpose. It can only be produced on a Mac, through private
163
+ API that changes between releases, so committing it is what makes the package reproducible.
164
+ To refresh after a macOS update, on a Mac with Xcode or the Command Line Tools:
165
+
166
+ ```bash
167
+ bun run extract # ~1 minute: loads WorkflowKit, dumps and serializes everything
168
+ bun install && bun test
169
+ bun run diff-data # what changed vs the committed data, and the semver bump it implies
170
+ bun run changelog # the same as a CHANGELOG.md section
171
+ ```
172
+
173
+ Both packages and the data are versioned together. A refresh that only adds actions or
174
+ parameters is a minor release. One that removes or retypes any is a major release, because the
175
+ generated catalogue is part of the type surface. Bump `package.json` and
176
+ `python/pyproject.toml` together and add the `bun run changelog` output to `CHANGELOG.md`.
177
+
178
+ The tools also dump Apple's gallery workflows, installed apps' App Intents actions and the raw
179
+ identifier list. Those files are local and gitignored.
180
+
181
+ ## Status
182
+
183
+ Data extracted on macOS 27.0 with Shortcuts 10.0 (see `data/provenance.json`). Generated files
184
+ declare minimum client version 900, which any current Shortcuts accepts. The private classes
185
+ the tools call can change with any release; the package itself depends only on the committed
186
+ data. Generated shortcuts import and run.
187
+
188
+ ## License
189
+
190
+ shortcutkit is licensed under the MIT license. See [`LICENSE`](LICENSE) for details.
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function demo(out: string): Promise<void>;
@@ -0,0 +1,69 @@
1
+ import type { ActionId } from "./generated/actions.js";
2
+ /** A localized string as the dumper resolves it: the English default. Parameter summaries keep their format string. */
3
+ export type Localized = string | {
4
+ format?: string;
5
+ title?: string;
6
+ possibleValues?: ParameterSummaryValue[];
7
+ };
8
+ export interface ParameterSummaryValue {
9
+ key?: string;
10
+ format?: string;
11
+ requiredValues?: Record<string, unknown>;
12
+ }
13
+ export interface ParameterDefinition {
14
+ Key: string;
15
+ /** WorkflowKit parameter class, e.g. "WFSwitchParameter"; decides the value encoding (see values.ts). */
16
+ Class: string;
17
+ Label?: string;
18
+ Placeholder?: string;
19
+ Description?: string;
20
+ DefaultValue?: unknown;
21
+ /** Choice labels for enumeration parameters. */
22
+ Items?: string[];
23
+ Hidden?: boolean;
24
+ RequiredResources?: unknown[];
25
+ [key: string]: unknown;
26
+ }
27
+ export interface ActionDefinition {
28
+ ActionClass?: string;
29
+ Name?: string;
30
+ Description?: {
31
+ DescriptionSummary?: string;
32
+ DescriptionInput?: string;
33
+ DescriptionResult?: string;
34
+ DescriptionNote?: string;
35
+ };
36
+ ActionKeywords?: string;
37
+ IconSymbol?: string;
38
+ IconColor?: string;
39
+ Parameters?: ParameterDefinition[];
40
+ ParameterSummary?: Localized;
41
+ Input?: {
42
+ ParameterKey?: string;
43
+ Types?: string[];
44
+ Required?: boolean;
45
+ Multiple?: boolean;
46
+ InputTypeDeterminesOutputType?: boolean;
47
+ };
48
+ Output?: {
49
+ OutputName?: string;
50
+ Types?: string[];
51
+ Multiple?: boolean;
52
+ DisclosureLevel?: string;
53
+ };
54
+ InputPassthrough?: boolean;
55
+ ResidentCompatible?: boolean;
56
+ RequiresUserInteraction?: boolean;
57
+ RequiredResources?: Array<string | {
58
+ resource: string;
59
+ [key: string]: unknown;
60
+ }>;
61
+ FillingProvider?: string;
62
+ AppIdentifier?: string;
63
+ [key: string]: unknown;
64
+ }
65
+ /** The full definition record for a built-in action, or undefined for identifiers the engine does not know. */
66
+ export declare function getDefinition(identifier: ActionId): ActionDefinition;
67
+ export declare function getDefinition(identifier: string): ActionDefinition | undefined;
68
+ /** Every built-in definition, keyed by identifier. */
69
+ export declare function allDefinitions(): Readonly<Record<string, ActionDefinition>>;