@openhands/extensions 0.14.0 → 0.16.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/.release-please-manifest.json +1 -1
- package/README.md +4 -1
- package/automations/README.md +22 -9
- package/automations/index.d.ts +126 -1
- package/automations/interface.json +90 -5
- package/automations/interface.schema.json +267 -7
- package/marketplaces/large-codebase.json +2 -2
- package/marketplaces/openhands-extensions.json +48 -48
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/python/openhands_extensions/_version.py +1 -1
- package/scripts/build-skills-catalog.mjs +76 -3
- package/skills/index.d.ts +21 -0
- package/skills/index.js +109 -52
- package/tests/test_interface_manifest.py +20 -0
- package/tests/test_skills_catalog.py +214 -4
package/README.md
CHANGED
|
@@ -182,7 +182,10 @@ Official skills and plugins for OpenHands — the open-source AI software engine
|
|
|
182
182
|
2. Create a new directory: `skills/<your-skill-name>/`
|
|
183
183
|
3. Add `skills/<your-skill-name>/SKILL.md`
|
|
184
184
|
4. (Optional) Add `README.md`, `references/`, `scripts/`, etc.
|
|
185
|
-
5.
|
|
185
|
+
5. Add an entry to `marketplaces/openhands-extensions.json` with a `category` — this is what the OpenHands Skills page uses to group the skill. Skills with no entry are grouped as "Uncategorized". Marketplace entries also require `.plugin/plugin.json` and vendor symlinks.
|
|
186
|
+
6. Submit a pull request
|
|
187
|
+
|
|
188
|
+
Valid skill categories: `automations`, `environment`, `code-hosting`, `agent-authoring`, `code-quality`, `integrations`, `writing`, `design`, `other`.
|
|
186
189
|
|
|
187
190
|
### Adding a Plugin
|
|
188
191
|
|
package/automations/README.md
CHANGED
|
@@ -177,13 +177,26 @@ extension surface tomorrow) rather than between entries, so each is stated once
|
|
|
177
177
|
Agent Canvas keeps its rendering components and reads every automation-specific datum from this file,
|
|
178
178
|
falling back to its built-in defaults when the manifest is absent or fails admission:
|
|
179
179
|
|
|
180
|
-
- **`routes`** - the list, setup, and
|
|
181
|
-
declared shape, so admission verifies they match what it mounted; the manifest is the single source
|
|
182
|
-
link construction.
|
|
183
|
-
- **`navigation`** - the sidebar entry
|
|
180
|
+
- **`routes`** - the list, setup, detail, and templates routes. The host must have a registration serving
|
|
181
|
+
each declared shape, so admission verifies they match what it mounted; the manifest is the single source
|
|
182
|
+
for link construction.
|
|
183
|
+
- **`navigation`** - the sidebar entry, the command-menu entry, and `subPages`: the ordered sub-page
|
|
184
|
+
navigation rendered inside the Automation interface, each item naming a `pages` entry with a label and
|
|
185
|
+
an icon slug from the host's closed icon map.
|
|
184
186
|
- **`pages`** - page-identity copy: the list title and subtitle, the detail back label, the edit-dialog
|
|
185
|
-
title. Generic chrome - buttons, toasts, empty states, validation
|
|
186
|
-
through the host's translations.
|
|
187
|
+
title, the templates title and description. Generic chrome - buttons, toasts, empty states, validation
|
|
188
|
+
sentences - stays host copy, rendered through the host's translations.
|
|
189
|
+
- **`pages.list.overview` / `filters` / `sort` / `insights`** - the list page's dashboard composition.
|
|
190
|
+
Every value here names something the host implements from a closed set, and the manifest picks and
|
|
191
|
+
captions it: `overview.tiles[].metric` names a host-computed value (`automations`, `needs-attention`,
|
|
192
|
+
`total-runs`, `average-duration`), filter option values name host predicates (`status`: enabled /
|
|
193
|
+
latest-run-failed / disabled; `trigger`: `event` matches event-triggered automations, `schedule`
|
|
194
|
+
everything else), `sort` values name host comparators, and `insights` captions the host's run-health
|
|
195
|
+
states and per-automation stats. The health precedence, the run sampling, the value formatting, the
|
|
196
|
+
relative-time rendering, and the filtered-empty state with its reset button are the host's - a manifest
|
|
197
|
+
cannot redefine them, only relabel what appears. Tile `detail` copy is plain substitution over the
|
|
198
|
+
metric's placeholder namespace (only the `automations` metric exposes `{{active}}`); `zeroDetail`
|
|
199
|
+
replaces `detail` while the value is zero.
|
|
187
200
|
- **`docsUrl`** - the automations documentation link, prefix-pinned to docs.openhands.dev by schema.
|
|
188
201
|
- **`attributes`** - the input surface of an existing Automation: which attributes can be set after
|
|
189
202
|
creation, keyed by the runtime-model property the host sends (`name`, `prompt`, `model`, `timeout`,
|
|
@@ -300,8 +313,8 @@ Recorded rather than resolved, because they need an owner outside this contract:
|
|
|
300
313
|
related fields onto one line, which reads better; if that matters, it is a host concern, not an entry's.
|
|
301
314
|
- **Assisted-setup completion.** The assisted flow ends at a conversation, so the host cannot emit a
|
|
302
315
|
completion event. Until something reports back, the ratio of direct to assisted setup is not measurable.
|
|
303
|
-
- **Delete confirmation and per-run views.** `interface.json` models the
|
|
304
|
-
and the
|
|
305
|
-
|
|
316
|
+
- **Delete confirmation and per-run views.** `interface.json` models the routes, the settable attributes,
|
|
317
|
+
and the dashboard and templates sub-pages; deletion and run logs remain host-owned surfaces with no
|
|
318
|
+
manifest data of their own yet.
|
|
306
319
|
- **Types from the schema.** `index.d.ts` is hand-written and mirrors `catalog.schema.json`. Generating it
|
|
307
320
|
would remove that second source of truth.
|
package/automations/index.d.ts
CHANGED
|
@@ -130,17 +130,142 @@ export interface AutomationInterfaceRoutes {
|
|
|
130
130
|
setup: string;
|
|
131
131
|
/** Carries the `:automationId` segment the host substitutes. */
|
|
132
132
|
detail: string;
|
|
133
|
+
/** The templates sub-page. Static: there is no parameter to substitute. */
|
|
134
|
+
templates: string;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** An icon name from the host's closed icon map. */
|
|
138
|
+
export type AutomationIconSlug =
|
|
139
|
+
| "layout-dashboard"
|
|
140
|
+
| "sparkles"
|
|
141
|
+
| "bot"
|
|
142
|
+
| "circle-alert"
|
|
143
|
+
| "activity"
|
|
144
|
+
| "timer";
|
|
145
|
+
|
|
146
|
+
/** The pages a sub-page navigation item may point at. */
|
|
147
|
+
export type AutomationSubPageId = "list" | "templates";
|
|
148
|
+
|
|
149
|
+
export interface AutomationSubPageNavItem {
|
|
150
|
+
/** The `pages` entry this item navigates to; its route comes from `routes`. */
|
|
151
|
+
page: AutomationSubPageId;
|
|
152
|
+
label: string;
|
|
153
|
+
icon: AutomationIconSlug;
|
|
133
154
|
}
|
|
134
155
|
|
|
135
156
|
export interface AutomationInterfaceNavigation {
|
|
136
157
|
sidebar: { label: string };
|
|
137
158
|
commandMenu: { title: string; description: string; keywords: string };
|
|
159
|
+
/** The ordered sub-page navigation of the Automation interface. */
|
|
160
|
+
subPages: AutomationSubPageNavItem[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** A value the host computes; a tile picks and captions it, never defines it. */
|
|
164
|
+
export type AutomationOverviewMetric =
|
|
165
|
+
| "automations"
|
|
166
|
+
| "needs-attention"
|
|
167
|
+
| "total-runs"
|
|
168
|
+
| "average-duration";
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* One summary tile. `detail` captions the value; `zeroDetail`, when present,
|
|
172
|
+
* replaces it while the value is zero. Both are plain substitution over the
|
|
173
|
+
* metric's placeholder namespace: only the `automations` metric exposes
|
|
174
|
+
* `{{active}}`, so every other tile's copy is literal.
|
|
175
|
+
*/
|
|
176
|
+
export interface AutomationOverviewTile {
|
|
177
|
+
metric: AutomationOverviewMetric;
|
|
178
|
+
label: string;
|
|
179
|
+
detail: string;
|
|
180
|
+
zeroDetail?: string;
|
|
181
|
+
icon: AutomationIconSlug;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface AutomationOverview {
|
|
185
|
+
/** Names the tiles section for assistive technology. */
|
|
186
|
+
label: string;
|
|
187
|
+
tiles: AutomationOverviewTile[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type AutomationStatusFilterValue =
|
|
191
|
+
| "all"
|
|
192
|
+
| "active"
|
|
193
|
+
| "failing"
|
|
194
|
+
| "disabled";
|
|
195
|
+
export type AutomationTriggerFilterValue = "all" | "schedule" | "event";
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* A filter dropdown. Values name predicates the host implements; the manifest
|
|
199
|
+
* supplies which appear and their labels. `label` is the control's accessible
|
|
200
|
+
* name. The `all` option is the host's default and reset target.
|
|
201
|
+
*/
|
|
202
|
+
export interface AutomationStatusFilter {
|
|
203
|
+
id: "status";
|
|
204
|
+
label: string;
|
|
205
|
+
options: { value: AutomationStatusFilterValue; label: string }[];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export interface AutomationTriggerFilter {
|
|
209
|
+
id: "trigger";
|
|
210
|
+
label: string;
|
|
211
|
+
options: { value: AutomationTriggerFilterValue; label: string }[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export type AutomationDashboardFilter =
|
|
215
|
+
| AutomationStatusFilter
|
|
216
|
+
| AutomationTriggerFilter;
|
|
217
|
+
|
|
218
|
+
/** A comparator the host implements, named from a closed set. */
|
|
219
|
+
export type AutomationSortValue = "last-run" | "runs" | "name";
|
|
220
|
+
|
|
221
|
+
export interface AutomationDashboardSort {
|
|
222
|
+
/** The control's accessible name. */
|
|
223
|
+
label: string;
|
|
224
|
+
options: { value: AutomationSortValue; label: string }[];
|
|
225
|
+
/** Must be one of the declared option values. */
|
|
226
|
+
default: AutomationSortValue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Copy for the per-automation run insights on cards and rows. The states,
|
|
231
|
+
* precedence, sampling, and value formatting are the host's; the manifest
|
|
232
|
+
* names them.
|
|
233
|
+
*/
|
|
234
|
+
export interface AutomationListInsights {
|
|
235
|
+
health: {
|
|
236
|
+
healthy: string;
|
|
237
|
+
failing: string;
|
|
238
|
+
running: string;
|
|
239
|
+
disabled: string;
|
|
240
|
+
neverRun: string;
|
|
241
|
+
checking: string;
|
|
242
|
+
};
|
|
243
|
+
lastRun: { label: string; never: string; justNow: string };
|
|
244
|
+
stats: { runs: string; recentSuccess: string; averageDuration: string };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* The templates sub-page identity. Its body - the catalog cards and their
|
|
249
|
+
* launch behavior - is the host's existing catalog surface.
|
|
250
|
+
*/
|
|
251
|
+
export interface AutomationTemplatesPage {
|
|
252
|
+
title: string;
|
|
253
|
+
description: string;
|
|
138
254
|
}
|
|
139
255
|
|
|
140
256
|
export interface AutomationInterfacePages {
|
|
141
|
-
list: {
|
|
257
|
+
list: {
|
|
258
|
+
title: string;
|
|
259
|
+
subtitle: string;
|
|
260
|
+
overview: AutomationOverview;
|
|
261
|
+
/** The filter dropdowns of the list page, in render order. */
|
|
262
|
+
filters: AutomationDashboardFilter[];
|
|
263
|
+
sort: AutomationDashboardSort;
|
|
264
|
+
insights: AutomationListInsights;
|
|
265
|
+
};
|
|
142
266
|
detail: { backLabel: string };
|
|
143
267
|
edit: { title: string };
|
|
268
|
+
templates: AutomationTemplatesPage;
|
|
144
269
|
}
|
|
145
270
|
|
|
146
271
|
export type AutomationAttributeType =
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"routes": {
|
|
4
4
|
"list": "/automations",
|
|
5
5
|
"setup": "/automations/new/:automationId",
|
|
6
|
-
"detail": "/automations/:automationId"
|
|
6
|
+
"detail": "/automations/:automationId",
|
|
7
|
+
"templates": "/automations/templates"
|
|
7
8
|
},
|
|
8
9
|
"navigation": {
|
|
9
10
|
"sidebar": { "label": "Automate" },
|
|
@@ -11,15 +12,99 @@
|
|
|
11
12
|
"title": "Automations",
|
|
12
13
|
"description": "Review scheduled and webhook automations.",
|
|
13
14
|
"keywords": "automate cron schedule webhook jobs"
|
|
14
|
-
}
|
|
15
|
+
},
|
|
16
|
+
"subPages": [
|
|
17
|
+
{ "page": "list", "label": "Dashboard", "icon": "layout-dashboard" },
|
|
18
|
+
{ "page": "templates", "label": "Templates", "icon": "sparkles" }
|
|
19
|
+
]
|
|
15
20
|
},
|
|
16
21
|
"pages": {
|
|
17
22
|
"list": {
|
|
18
|
-
"title": "
|
|
19
|
-
"subtitle": "
|
|
23
|
+
"title": "Dashboard",
|
|
24
|
+
"subtitle": "Health, activity, and run performance across your automations.",
|
|
25
|
+
"overview": {
|
|
26
|
+
"label": "Automation overview",
|
|
27
|
+
"tiles": [
|
|
28
|
+
{
|
|
29
|
+
"metric": "automations",
|
|
30
|
+
"label": "Automations",
|
|
31
|
+
"detail": "{{active}} active",
|
|
32
|
+
"icon": "bot"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"metric": "needs-attention",
|
|
36
|
+
"label": "Needs attention",
|
|
37
|
+
"detail": "Latest run failed",
|
|
38
|
+
"zeroDetail": "No latest-run failures",
|
|
39
|
+
"icon": "circle-alert"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"metric": "total-runs",
|
|
43
|
+
"label": "Total runs",
|
|
44
|
+
"detail": "Across loaded automations",
|
|
45
|
+
"icon": "activity"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"metric": "average-duration",
|
|
49
|
+
"label": "Average duration",
|
|
50
|
+
"detail": "Recent completed runs",
|
|
51
|
+
"icon": "timer"
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"filters": [
|
|
56
|
+
{
|
|
57
|
+
"id": "status",
|
|
58
|
+
"label": "Filter by status",
|
|
59
|
+
"options": [
|
|
60
|
+
{ "value": "all", "label": "All statuses" },
|
|
61
|
+
{ "value": "active", "label": "Active" },
|
|
62
|
+
{ "value": "failing", "label": "Needs attention" },
|
|
63
|
+
{ "value": "disabled", "label": "Disabled" }
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "trigger",
|
|
68
|
+
"label": "Filter by trigger",
|
|
69
|
+
"options": [
|
|
70
|
+
{ "value": "all", "label": "All triggers" },
|
|
71
|
+
{ "value": "schedule", "label": "Scheduled" },
|
|
72
|
+
{ "value": "event", "label": "Event-driven" }
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"sort": {
|
|
77
|
+
"label": "Sort automations",
|
|
78
|
+
"default": "last-run",
|
|
79
|
+
"options": [
|
|
80
|
+
{ "value": "last-run", "label": "Latest run" },
|
|
81
|
+
{ "value": "runs", "label": "Most runs" },
|
|
82
|
+
{ "value": "name", "label": "Name" }
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"insights": {
|
|
86
|
+
"health": {
|
|
87
|
+
"healthy": "Healthy",
|
|
88
|
+
"failing": "Failing",
|
|
89
|
+
"running": "Running",
|
|
90
|
+
"disabled": "Disabled",
|
|
91
|
+
"neverRun": "Never run",
|
|
92
|
+
"checking": "Checking"
|
|
93
|
+
},
|
|
94
|
+
"lastRun": { "label": "Last run", "never": "Never", "justNow": "Just now" },
|
|
95
|
+
"stats": {
|
|
96
|
+
"runs": "Runs",
|
|
97
|
+
"recentSuccess": "Recent success",
|
|
98
|
+
"averageDuration": "Avg. duration"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
20
101
|
},
|
|
21
102
|
"detail": { "backLabel": "Back to Automations" },
|
|
22
|
-
"edit": { "title": "Edit automation" }
|
|
103
|
+
"edit": { "title": "Edit automation" },
|
|
104
|
+
"templates": {
|
|
105
|
+
"title": "Templates",
|
|
106
|
+
"description": "Browse proven automations and beta ideas, then launch one into a conversation to tailor it to your work."
|
|
107
|
+
}
|
|
23
108
|
},
|
|
24
109
|
"docsUrl": "https://docs.openhands.dev/openhands/usage/automations/overview",
|
|
25
110
|
"attributes": {
|
|
@@ -26,17 +26,21 @@
|
|
|
26
26
|
"description": "The routes of the Automation interface. The host must have a registration serving each declared shape, so admission verifies they match what it mounted; the manifest is the single source for link construction.",
|
|
27
27
|
"type": "object",
|
|
28
28
|
"additionalProperties": false,
|
|
29
|
-
"required": ["list", "setup", "detail"],
|
|
29
|
+
"required": ["list", "setup", "detail", "templates"],
|
|
30
30
|
"properties": {
|
|
31
31
|
"list": { "$ref": "#/$defs/routePath" },
|
|
32
32
|
"setup": { "$ref": "#/$defs/parameterizedRoutePath" },
|
|
33
|
-
"detail": { "$ref": "#/$defs/parameterizedRoutePath" }
|
|
33
|
+
"detail": { "$ref": "#/$defs/parameterizedRoutePath" },
|
|
34
|
+
"templates": {
|
|
35
|
+
"description": "The templates sub-page. Static: there is no parameter to substitute.",
|
|
36
|
+
"allOf": [{ "$ref": "#/$defs/routePath" }, { "not": { "pattern": ":" } }]
|
|
37
|
+
}
|
|
34
38
|
}
|
|
35
39
|
},
|
|
36
40
|
"navigation": {
|
|
37
41
|
"type": "object",
|
|
38
42
|
"additionalProperties": false,
|
|
39
|
-
"required": ["sidebar", "commandMenu"],
|
|
43
|
+
"required": ["sidebar", "commandMenu", "subPages"],
|
|
40
44
|
"properties": {
|
|
41
45
|
"sidebar": {
|
|
42
46
|
"type": "object",
|
|
@@ -53,22 +57,46 @@
|
|
|
53
57
|
"description": { "$ref": "#/$defs/copy" },
|
|
54
58
|
"keywords": { "$ref": "#/$defs/copy" }
|
|
55
59
|
}
|
|
60
|
+
},
|
|
61
|
+
"subPages": {
|
|
62
|
+
"description": "The ordered sub-page navigation of the Automation interface. Each page id may appear once; the host's admission checks that, since uniqueItems cannot see through differing labels.",
|
|
63
|
+
"type": "array",
|
|
64
|
+
"minItems": 1,
|
|
65
|
+
"maxItems": 2,
|
|
66
|
+
"uniqueItems": true,
|
|
67
|
+
"items": { "$ref": "#/$defs/subPageNavItem" }
|
|
56
68
|
}
|
|
57
69
|
}
|
|
58
70
|
},
|
|
59
71
|
"pages": {
|
|
60
|
-
"description": "Page-identity copy. Generic chrome - buttons, toasts, empty states, validation sentences - stays host copy, rendered through the host's translations.",
|
|
72
|
+
"description": "Page-identity copy, plus the list page's dashboard composition. Generic chrome - buttons, toasts, empty states, validation sentences - stays host copy, rendered through the host's translations.",
|
|
61
73
|
"type": "object",
|
|
62
74
|
"additionalProperties": false,
|
|
63
|
-
"required": ["list", "detail", "edit"],
|
|
75
|
+
"required": ["list", "detail", "edit", "templates"],
|
|
64
76
|
"properties": {
|
|
65
77
|
"list": {
|
|
66
78
|
"type": "object",
|
|
67
79
|
"additionalProperties": false,
|
|
68
|
-
"required": ["title", "subtitle"],
|
|
80
|
+
"required": ["title", "subtitle", "overview", "filters", "sort", "insights"],
|
|
69
81
|
"properties": {
|
|
70
82
|
"title": { "$ref": "#/$defs/copy" },
|
|
71
|
-
"subtitle": { "$ref": "#/$defs/copy" }
|
|
83
|
+
"subtitle": { "$ref": "#/$defs/copy" },
|
|
84
|
+
"overview": { "$ref": "#/$defs/overview" },
|
|
85
|
+
"filters": {
|
|
86
|
+
"description": "The filter dropdowns of the list page, in render order. Each filter id may appear once; the host's admission checks that.",
|
|
87
|
+
"type": "array",
|
|
88
|
+
"minItems": 1,
|
|
89
|
+
"maxItems": 2,
|
|
90
|
+
"uniqueItems": true,
|
|
91
|
+
"items": {
|
|
92
|
+
"oneOf": [
|
|
93
|
+
{ "$ref": "#/$defs/statusFilter" },
|
|
94
|
+
{ "$ref": "#/$defs/triggerFilter" }
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"sort": { "$ref": "#/$defs/sort" },
|
|
99
|
+
"insights": { "$ref": "#/$defs/insights" }
|
|
72
100
|
}
|
|
73
101
|
},
|
|
74
102
|
"detail": {
|
|
@@ -82,6 +110,16 @@
|
|
|
82
110
|
"additionalProperties": false,
|
|
83
111
|
"required": ["title"],
|
|
84
112
|
"properties": { "title": { "$ref": "#/$defs/copy" } }
|
|
113
|
+
},
|
|
114
|
+
"templates": {
|
|
115
|
+
"description": "The templates sub-page identity. Its body - the catalog cards and their launch behavior - is the host's existing catalog surface.",
|
|
116
|
+
"type": "object",
|
|
117
|
+
"additionalProperties": false,
|
|
118
|
+
"required": ["title", "description"],
|
|
119
|
+
"properties": {
|
|
120
|
+
"title": { "$ref": "#/$defs/copy" },
|
|
121
|
+
"description": { "$ref": "#/$defs/copy" }
|
|
122
|
+
}
|
|
85
123
|
}
|
|
86
124
|
}
|
|
87
125
|
},
|
|
@@ -238,6 +276,228 @@
|
|
|
238
276
|
"minItems": 1,
|
|
239
277
|
"uniqueItems": true,
|
|
240
278
|
"items": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }
|
|
279
|
+
},
|
|
280
|
+
"iconSlug": {
|
|
281
|
+
"description": "An icon name from the host's closed icon map. The manifest picks from what the host ships; it cannot supply artwork.",
|
|
282
|
+
"enum": [
|
|
283
|
+
"layout-dashboard",
|
|
284
|
+
"sparkles",
|
|
285
|
+
"bot",
|
|
286
|
+
"circle-alert",
|
|
287
|
+
"activity",
|
|
288
|
+
"timer"
|
|
289
|
+
]
|
|
290
|
+
},
|
|
291
|
+
"subPageNavItem": {
|
|
292
|
+
"type": "object",
|
|
293
|
+
"additionalProperties": false,
|
|
294
|
+
"required": ["page", "label", "icon"],
|
|
295
|
+
"properties": {
|
|
296
|
+
"page": {
|
|
297
|
+
"description": "The pages entry this item navigates to; its route comes from routes.list or routes.templates.",
|
|
298
|
+
"enum": ["list", "templates"]
|
|
299
|
+
},
|
|
300
|
+
"label": { "$ref": "#/$defs/copy" },
|
|
301
|
+
"icon": { "$ref": "#/$defs/iconSlug" }
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
"overview": {
|
|
305
|
+
"description": "The summary tiles above the list. label names the section for assistive technology.",
|
|
306
|
+
"type": "object",
|
|
307
|
+
"additionalProperties": false,
|
|
308
|
+
"required": ["label", "tiles"],
|
|
309
|
+
"properties": {
|
|
310
|
+
"label": { "$ref": "#/$defs/copy" },
|
|
311
|
+
"tiles": {
|
|
312
|
+
"description": "Each metric may appear once; the host's admission checks that.",
|
|
313
|
+
"type": "array",
|
|
314
|
+
"minItems": 1,
|
|
315
|
+
"maxItems": 8,
|
|
316
|
+
"uniqueItems": true,
|
|
317
|
+
"items": { "$ref": "#/$defs/overviewTile" }
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
"overviewTile": {
|
|
322
|
+
"description": "One summary tile. The metric names a value the host computes - a tile picks and captions it, never defines it. detail is the caption under the value; zeroDetail, when present, replaces it while the value is zero. Both are plain substitution over the metric's placeholder namespace: only the automations metric exposes {{active}}, so every other tile's copy is literal.",
|
|
323
|
+
"type": "object",
|
|
324
|
+
"additionalProperties": false,
|
|
325
|
+
"required": ["metric", "label", "detail", "icon"],
|
|
326
|
+
"properties": {
|
|
327
|
+
"metric": {
|
|
328
|
+
"enum": ["automations", "needs-attention", "total-runs", "average-duration"]
|
|
329
|
+
},
|
|
330
|
+
"label": { "$ref": "#/$defs/copy" },
|
|
331
|
+
"detail": { "$ref": "#/$defs/copy" },
|
|
332
|
+
"zeroDetail": { "$ref": "#/$defs/copy" },
|
|
333
|
+
"icon": { "$ref": "#/$defs/iconSlug" }
|
|
334
|
+
},
|
|
335
|
+
"allOf": [
|
|
336
|
+
{
|
|
337
|
+
"if": {
|
|
338
|
+
"properties": { "metric": { "const": "automations" } },
|
|
339
|
+
"required": ["metric"]
|
|
340
|
+
},
|
|
341
|
+
"then": {
|
|
342
|
+
"properties": {
|
|
343
|
+
"detail": { "not": { "pattern": "\\{\\{(?!active\\}\\})" } },
|
|
344
|
+
"zeroDetail": { "not": { "pattern": "\\{\\{(?!active\\}\\})" } }
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
"else": {
|
|
348
|
+
"properties": {
|
|
349
|
+
"detail": { "not": { "pattern": "\\{\\{" } },
|
|
350
|
+
"zeroDetail": { "not": { "pattern": "\\{\\{" } }
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
]
|
|
355
|
+
},
|
|
356
|
+
"statusFilter": {
|
|
357
|
+
"description": "The status filter. Values name predicates the host implements over an automation and its derived health; the manifest supplies which appear and their labels. The all option is the host's default and reset target, so it must be offered.",
|
|
358
|
+
"type": "object",
|
|
359
|
+
"additionalProperties": false,
|
|
360
|
+
"required": ["id", "label", "options"],
|
|
361
|
+
"properties": {
|
|
362
|
+
"id": { "const": "status" },
|
|
363
|
+
"label": {
|
|
364
|
+
"description": "The control's accessible name.",
|
|
365
|
+
"$ref": "#/$defs/copy"
|
|
366
|
+
},
|
|
367
|
+
"options": {
|
|
368
|
+
"description": "Each value may appear once; the host's admission checks that.",
|
|
369
|
+
"type": "array",
|
|
370
|
+
"minItems": 2,
|
|
371
|
+
"maxItems": 8,
|
|
372
|
+
"uniqueItems": true,
|
|
373
|
+
"items": {
|
|
374
|
+
"type": "object",
|
|
375
|
+
"additionalProperties": false,
|
|
376
|
+
"required": ["value", "label"],
|
|
377
|
+
"properties": {
|
|
378
|
+
"value": { "enum": ["all", "active", "failing", "disabled"] },
|
|
379
|
+
"label": { "$ref": "#/$defs/copy" }
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
"contains": {
|
|
383
|
+
"type": "object",
|
|
384
|
+
"required": ["value"],
|
|
385
|
+
"properties": { "value": { "const": "all" } }
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
"triggerFilter": {
|
|
391
|
+
"description": "The trigger filter. Like the status filter, values name host-implemented predicates: event matches event-triggered automations, schedule everything else.",
|
|
392
|
+
"type": "object",
|
|
393
|
+
"additionalProperties": false,
|
|
394
|
+
"required": ["id", "label", "options"],
|
|
395
|
+
"properties": {
|
|
396
|
+
"id": { "const": "trigger" },
|
|
397
|
+
"label": {
|
|
398
|
+
"description": "The control's accessible name.",
|
|
399
|
+
"$ref": "#/$defs/copy"
|
|
400
|
+
},
|
|
401
|
+
"options": {
|
|
402
|
+
"description": "Each value may appear once; the host's admission checks that.",
|
|
403
|
+
"type": "array",
|
|
404
|
+
"minItems": 2,
|
|
405
|
+
"maxItems": 8,
|
|
406
|
+
"uniqueItems": true,
|
|
407
|
+
"items": {
|
|
408
|
+
"type": "object",
|
|
409
|
+
"additionalProperties": false,
|
|
410
|
+
"required": ["value", "label"],
|
|
411
|
+
"properties": {
|
|
412
|
+
"value": { "enum": ["all", "schedule", "event"] },
|
|
413
|
+
"label": { "$ref": "#/$defs/copy" }
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
"contains": {
|
|
417
|
+
"type": "object",
|
|
418
|
+
"required": ["value"],
|
|
419
|
+
"properties": { "value": { "const": "all" } }
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
"sort": {
|
|
425
|
+
"description": "The sort dropdown. Values name comparators the host implements. default must be one of the declared option values; the host's admission checks that, as schemas cannot cheaply.",
|
|
426
|
+
"type": "object",
|
|
427
|
+
"additionalProperties": false,
|
|
428
|
+
"required": ["label", "options", "default"],
|
|
429
|
+
"properties": {
|
|
430
|
+
"label": {
|
|
431
|
+
"description": "The control's accessible name.",
|
|
432
|
+
"$ref": "#/$defs/copy"
|
|
433
|
+
},
|
|
434
|
+
"options": {
|
|
435
|
+
"description": "Each value may appear once; the host's admission checks that.",
|
|
436
|
+
"type": "array",
|
|
437
|
+
"minItems": 1,
|
|
438
|
+
"maxItems": 3,
|
|
439
|
+
"uniqueItems": true,
|
|
440
|
+
"items": {
|
|
441
|
+
"type": "object",
|
|
442
|
+
"additionalProperties": false,
|
|
443
|
+
"required": ["value", "label"],
|
|
444
|
+
"properties": {
|
|
445
|
+
"value": { "$ref": "#/$defs/sortValue" },
|
|
446
|
+
"label": { "$ref": "#/$defs/copy" }
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"default": { "$ref": "#/$defs/sortValue" }
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
"sortValue": { "enum": ["last-run", "runs", "name"] },
|
|
454
|
+
"insights": {
|
|
455
|
+
"description": "Copy for the per-automation run insights on cards and rows. The states, precedence, sampling, and value formatting are the host's; the manifest names them.",
|
|
456
|
+
"type": "object",
|
|
457
|
+
"additionalProperties": false,
|
|
458
|
+
"required": ["health", "lastRun", "stats"],
|
|
459
|
+
"properties": {
|
|
460
|
+
"health": {
|
|
461
|
+
"type": "object",
|
|
462
|
+
"additionalProperties": false,
|
|
463
|
+
"required": [
|
|
464
|
+
"healthy",
|
|
465
|
+
"failing",
|
|
466
|
+
"running",
|
|
467
|
+
"disabled",
|
|
468
|
+
"neverRun",
|
|
469
|
+
"checking"
|
|
470
|
+
],
|
|
471
|
+
"properties": {
|
|
472
|
+
"healthy": { "$ref": "#/$defs/copy" },
|
|
473
|
+
"failing": { "$ref": "#/$defs/copy" },
|
|
474
|
+
"running": { "$ref": "#/$defs/copy" },
|
|
475
|
+
"disabled": { "$ref": "#/$defs/copy" },
|
|
476
|
+
"neverRun": { "$ref": "#/$defs/copy" },
|
|
477
|
+
"checking": { "$ref": "#/$defs/copy" }
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
"lastRun": {
|
|
481
|
+
"type": "object",
|
|
482
|
+
"additionalProperties": false,
|
|
483
|
+
"required": ["label", "never", "justNow"],
|
|
484
|
+
"properties": {
|
|
485
|
+
"label": { "$ref": "#/$defs/copy" },
|
|
486
|
+
"never": { "$ref": "#/$defs/copy" },
|
|
487
|
+
"justNow": { "$ref": "#/$defs/copy" }
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
"stats": {
|
|
491
|
+
"type": "object",
|
|
492
|
+
"additionalProperties": false,
|
|
493
|
+
"required": ["runs", "recentSuccess", "averageDuration"],
|
|
494
|
+
"properties": {
|
|
495
|
+
"runs": { "$ref": "#/$defs/copy" },
|
|
496
|
+
"recentSuccess": { "$ref": "#/$defs/copy" },
|
|
497
|
+
"averageDuration": { "$ref": "#/$defs/copy" }
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
241
501
|
}
|
|
242
502
|
}
|
|
243
503
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"name": "add-javadoc",
|
|
15
15
|
"source": "./skills/add-javadoc",
|
|
16
16
|
"description": "Add comprehensive JavaDoc documentation to Java classes and methods. Use when documenting Java code, adding API documentation, or improving code documentation.",
|
|
17
|
-
"category": "
|
|
17
|
+
"category": "code-quality",
|
|
18
18
|
"keywords": [
|
|
19
19
|
"javadoc",
|
|
20
20
|
"java",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"name": "spark-version-upgrade",
|
|
53
53
|
"source": "./skills/spark-version-upgrade",
|
|
54
54
|
"description": "Upgrade Apache Spark applications between major versions (2.x→3.x, 3.x→4.x). Covers build files, deprecated APIs, configuration changes, SQL/DataFrame updates, and test validation.",
|
|
55
|
-
"category": "
|
|
55
|
+
"category": "environment",
|
|
56
56
|
"keywords": [
|
|
57
57
|
"spark",
|
|
58
58
|
"upgrade",
|