@vention/vention-skills 0.10.15 → 0.10.16
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/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/skills/vention-design/SKILL.md +1 -1
- package/skills/vention-machine-logic/SKILL.md +1 -1
- package/skills/vention-machine-logic-hmi/SKILL.md +3 -3
- package/skills/vention-machine-logic-hmi/examples/indexing-station-hmi/customui/src/app.tsx +112 -61
- package/skills/vention-machine-logic-hmi/examples/indexing-station-hmi/customui/src/pages/operate-page.tsx +3 -3
- package/skills/vention-machine-logic-hmi/examples/indexing-station-hmi/customui/src/pages/recipes-page.tsx +4 -4
- package/skills/vention-monitoring/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vention skills
|
|
2
2
|
|
|
3
|
-
Version 0.10.
|
|
3
|
+
Version 0.10.16. Skills for coding agents that work with Vention machines, packaged as one plugin, `vention`, in the `vention-skills` marketplace.
|
|
4
4
|
|
|
5
5
|
| Skill | What it does |
|
|
6
6
|
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vention/vention-skills",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.16",
|
|
4
4
|
"description": "Vention skills for coding agents: write MachineLogic applications, build machine designs, and diagnose deployed machines.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "vention",
|
|
4
|
-
"version": "0.10.
|
|
4
|
+
"version": "0.10.16",
|
|
5
5
|
"description": "Vention skills for coding agents: write MachineLogic applications, build machine designs, and diagnose deployed machines.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Vention"
|
|
@@ -3,7 +3,7 @@ name: vention-design
|
|
|
3
3
|
description: Create, build and edit Vention machine designs and design graphs for agentic layout. Use when the user wants to start a new design, lay out an automation cell, add or reposition components in a Vention design, generate a machine layout from a description, add or place a floor plan image under a design, list a design's versions, or inspect an existing design graph. Trigger on MachineBuilder designs, design graphs, assembly graphs, extrusions, actuators, robot mounting, cell footprints, floor plans, or a machine-builder URL.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.10.
|
|
6
|
+
version: "0.10.16"
|
|
7
7
|
author: Vention
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ name: vention-machine-logic
|
|
|
3
3
|
description: Write, edit, validate, and deploy MachineLogic Python applications for Vention machines with the machine-logic-sdk and the Vention CLI. Load it before writing or changing any Python that talks to a Vention machine, however short, since device names and version-specific SDK calls come from here. Use to program a Vention machine or MachineMotion controller, drive actuators, conveyors, robots, pneumatics, or digital I/O, change an existing application, build a state machine, debug from logs, or pull, push, or link with the Vention CLI (vention or vn). Trigger on MachineLogic, machine-logic-sdk, MachineMotion, MachineBuilder applications, the Vention CLI, or a directory holding .machine-code-app-directory-info.json. Printing what the machine or robot holds now (positions, taught targets, calibration, I/O) is a program: files on disk hold only as-designed values. Not for explaining an existing machine or its configuration in words when no program is asked for, nor for Python that never touches the machine.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.10.
|
|
6
|
+
version: "0.10.16"
|
|
7
7
|
machine-logic-sdk: ">=3.0,<4"
|
|
8
8
|
author: Vention
|
|
9
9
|
---
|
|
@@ -3,7 +3,7 @@ name: vention-machine-logic-hmi
|
|
|
3
3
|
description: Build or edit the custom operator HMI of a MachineLogic application, the React touch screen in customui/ that runs in MachineBuilder and on the MachineMotion pendant, wired to the application's Python process through vention-communication. Use when the user asks for an operator screen, a custom HMI or UI, a touch panel, start and stop buttons, live machine state on screen, or recipes an operator picks, for a Vention machine or inside a directory holding .machine-code-app-directory-info.json. Uses @vention/machine-ui, @vention/machine-apps-components and @vention/machine-logic-ui-sdk. Do not use for the no-code HMI Builder, or for the Python motion logic alone (that is vention-machine-logic).
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.10.
|
|
6
|
+
version: "0.10.16"
|
|
7
7
|
author: Vention
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -165,7 +165,7 @@ The machine-apps-components README is behind its code: `NavigationBar` takes `Na
|
|
|
165
165
|
- Confirm anything that starts motion or deletes data in a `VentionModal` with `isTouchDevice`, and say in it what will move.
|
|
166
166
|
- `VentionButton` variants are `filled-brand`, `filled`, `outline`, `text-only`, `shaded` and `destructive`. MUI's `contained` and `outlined` do not exist on it, and neither does a `color` prop.
|
|
167
167
|
- Start is green and Stop is red, both set through the `StatusTopBar` button's `backgroundColor`, `backgroundColorHover` and `textColor`.
|
|
168
|
-
- A `LogsPanel` row cuts `message` and `description` to one line and shows the rest only on hover. Keep `message` to a few words saying what happened, put the cause and what to do next in `description`, and open the whole entry in a `VentionModal` from `onLogClick`. Raise every error
|
|
168
|
+
- A `LogsPanel` row cuts `message` and `description` to one line and shows the rest only on hover. Keep `message` to a few words saying what happened, put the cause and what to do next in `description`, and open the whole entry in a `VentionModal` from `onLogClick`. Log the HMI's own command failures there too, beside the server's events. Raise every error as a banner on whatever page is open, whose View button opens that entry on the Logs page; the banner fades after a few seconds, and the Logs tab shows a red count of the errors logged since that page was last opened, as the example's `app.tsx` does. Alerts float over the page just under the `StatusTopBar`, never in the page's flow, so one appearing never moves the layout.
|
|
169
169
|
|
|
170
170
|
## Validate before you push
|
|
171
171
|
|
|
@@ -180,7 +180,7 @@ The HMI drives physical machinery that can injure someone.
|
|
|
180
180
|
|
|
181
181
|
- Start never fires on page load, on reconnect, or from a stream message. Only an operator's tap, confirmed in a modal, starts motion.
|
|
182
182
|
- Start and Stop live in the `StatusTopBar`, so they are on every page. Do not repeat them on a page. Raise the bar above `theme.zIndex.modal`, as the example's `app.tsx` does, or an open `VentionModal` covers Stop.
|
|
183
|
-
- Stop is disabled until this page load has received its first status, since no Stop can reach the app before then; show why next to it and say to use the emergency stop if the machine moves. After that, Stop stays enabled unless the station is known to be ready or already stopping, as the example's `canStop` does. A fault is neither, so Stop stays enabled there, and so it does while the stream is disconnected: a dropped stream may hide a moving machine. When Stop fails, say it did not reach the station and to use the emergency stop. Every other command is disabled while disconnected.
|
|
183
|
+
- Stop is disabled until this page load has received its first status, since no Stop can reach the app before then; show why next to it and say to use the emergency stop if the machine moves. After that, Stop stays enabled unless the station is known to be ready or already stopping, as the example's `canStop` does. A fault is neither, so Stop stays enabled there, and so it does while the stream is disconnected: a dropped stream may hide a moving machine. When Stop fails, say it did not reach the station and to use the emergency stop, in an alert that stays until the operator closes it. Every other command is disabled while disconnected.
|
|
184
184
|
- A tap on Stop shows at once. While the station stops, the Stop button reads "Stopping…" (derive that label from the streamed state and `connected`, as the example's `isStopping(status, connected)` does, never from a tapped flag alone: once the stream drops it reads "Stop" again and stays pressable), the Operate page's progress bar marks where the run now ends (the cycle in progress amber, the cancelled ones hatched and struck through), and a line by the heading says the emergency stop halts at once. Say it on the screen the operator already watches rather than in a separate alert.
|
|
185
185
|
- Send Start with a `timeoutMs` and an abort signal, and abort it when the stream drops. A Start the operator can no longer see must not land later; say it was not confirmed and to check the station.
|
|
186
186
|
- The HMI never offers a way around an emergency stop, safety interlock, light curtain or guard, not even a hidden one for testing.
|
|
@@ -2,9 +2,9 @@ import { Box } from "@mui/material"
|
|
|
2
2
|
import { IconBook, IconHistory, IconLayoutDashboard, IconPlayerPlayFilled, IconPlayerStopFilled } from "@tabler/icons-react"
|
|
3
3
|
import { NavigationBar, StatusTopBar } from "@vention/machine-apps-components"
|
|
4
4
|
import type { LogEntry, LogType } from "@vention/machine-apps-components"
|
|
5
|
-
import { COLORS, VentionAlert, VentionModal } from "@vention/machine-ui"
|
|
6
|
-
import { useEffect, useRef, useState } from "react"
|
|
7
|
-
import { Navigate, Route, Routes, useNavigate } from "react-router-dom"
|
|
5
|
+
import { COLORS, VentionAlert, VentionCounter, VentionModal } from "@vention/machine-ui"
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react"
|
|
7
|
+
import { Navigate, Route, Routes, useLocation, useNavigate } from "react-router-dom"
|
|
8
8
|
import { client, openEvents, openStatus, STATUS_STALL_MS } from "./client"
|
|
9
9
|
import type { Event, Recipe } from "./gen/app_pb"
|
|
10
10
|
import { LogsPage } from "./pages/logs-page"
|
|
@@ -19,6 +19,8 @@ const NAV_ICON_SIZE = 42
|
|
|
19
19
|
const TOP_BAR_ICON_SIZE = 32
|
|
20
20
|
// A Start that has not been answered by then is abandoned rather than left to land later.
|
|
21
21
|
const START_TIMEOUT_MS = 5000
|
|
22
|
+
// The Logs tab's unread count keeps an error after its banner fades.
|
|
23
|
+
const ERROR_BANNER_MS = 8000
|
|
22
24
|
|
|
23
25
|
function toLogLevel(level: string): LogType {
|
|
24
26
|
if (level === "error") return "error"
|
|
@@ -26,37 +28,40 @@ function toLogLevel(level: string): LogType {
|
|
|
26
28
|
return "info"
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
/** The server's events, plus the HMI's own command failures, newest first. */
|
|
32
|
+
function useEventLog(): { entries: LogEntry[]; addEntry: (level: LogType, message: string, description: string) => string } {
|
|
30
33
|
const { value: latestEvent } = useStream<Event>(openEvents)
|
|
31
34
|
const [entries, setEntries] = useState<LogEntry[]>([])
|
|
32
35
|
const nextId = useRef(0)
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
if (latestEvent === undefined) return
|
|
37
|
+
const addEntry = useCallback((level: LogType, message: string, description: string, date = new Date().toISOString()) => {
|
|
36
38
|
nextId.current += 1
|
|
37
|
-
const entry: LogEntry = {
|
|
38
|
-
id: String(nextId.current),
|
|
39
|
-
date: latestEvent.timestamp,
|
|
40
|
-
level: toLogLevel(latestEvent.level),
|
|
41
|
-
code: latestEvent.level.toUpperCase(),
|
|
42
|
-
message: latestEvent.message,
|
|
43
|
-
description: latestEvent.detail,
|
|
44
|
-
}
|
|
39
|
+
const entry: LogEntry = { id: String(nextId.current), date, level, code: level.toUpperCase(), message, description }
|
|
45
40
|
setEntries(previous => [entry, ...previous].slice(0, MAX_LOG_ENTRIES))
|
|
46
|
-
|
|
41
|
+
return entry.id
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (latestEvent !== undefined) addEntry(toLogLevel(latestEvent.level), latestEvent.message, latestEvent.detail, latestEvent.timestamp)
|
|
46
|
+
}, [latestEvent, addEntry])
|
|
47
47
|
|
|
48
|
-
return entries
|
|
48
|
+
return { entries, addEntry }
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function App() {
|
|
52
52
|
const { value: status, connected } = useStream(openStatus, STATUS_STALL_MS)
|
|
53
|
-
const logEntries = useEventLog()
|
|
54
|
-
const [commandError, setCommandError] = useState("")
|
|
53
|
+
const { entries: logEntries, addEntry } = useEventLog()
|
|
55
54
|
const navigate = useNavigate()
|
|
56
|
-
|
|
55
|
+
const isOnLogsPage = useLocation().pathname === "/logs"
|
|
56
|
+
// The latest error shows as a banner on every page until it fades; View opens the whole entry on the Logs page.
|
|
57
57
|
const [errorEntry, setErrorEntry] = useState<LogEntry | undefined>(undefined)
|
|
58
58
|
const [openLogEntry, setOpenLogEntry] = useState<LogEntry | undefined>(undefined)
|
|
59
|
+
// A Stop that did not land never fades: the operator must know to use the emergency stop.
|
|
60
|
+
const [stopFailure, setStopFailure] = useState("")
|
|
61
|
+
const stopFailureIds = useRef(new Set<string>())
|
|
62
|
+
const [lastSeenLogId, setLastSeenLogId] = useState(0)
|
|
59
63
|
const latestEntry = logEntries[0]
|
|
64
|
+
const unseenErrors = logEntries.filter(entry => entry.level === "error" && Number(entry.id) > lastSeenLogId).length
|
|
60
65
|
const state = describeState(status, connected)
|
|
61
66
|
|
|
62
67
|
const [recipe, setRecipe] = useState<Recipe | undefined>(undefined)
|
|
@@ -64,14 +69,26 @@ export function App() {
|
|
|
64
69
|
const startRequest = useRef<AbortController | undefined>(undefined)
|
|
65
70
|
const startable = canStart(status, connected) && recipe !== undefined
|
|
66
71
|
|
|
72
|
+
const reportError = useCallback((message: string, detail: string) => void addEntry("error", message, detail), [addEntry])
|
|
73
|
+
|
|
67
74
|
useEffect(() => {
|
|
68
75
|
if (!connected) startRequest.current?.abort()
|
|
69
76
|
}, [connected])
|
|
70
77
|
|
|
71
78
|
useEffect(() => {
|
|
72
|
-
if (latestEntry?.level === "error") setErrorEntry(latestEntry)
|
|
79
|
+
if (latestEntry?.level === "error" && !stopFailureIds.current.has(latestEntry.id)) setErrorEntry(latestEntry)
|
|
73
80
|
}, [latestEntry])
|
|
74
81
|
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (errorEntry === undefined) return
|
|
84
|
+
const timer = setTimeout(() => setErrorEntry(undefined), ERROR_BANNER_MS)
|
|
85
|
+
return () => clearTimeout(timer)
|
|
86
|
+
}, [errorEntry])
|
|
87
|
+
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (isOnLogsPage && latestEntry !== undefined) setLastSeenLogId(Number(latestEntry.id))
|
|
90
|
+
}, [isOnLogsPage, latestEntry])
|
|
91
|
+
|
|
75
92
|
const viewError = () => {
|
|
76
93
|
setOpenLogEntry(errorEntry)
|
|
77
94
|
setErrorEntry(undefined)
|
|
@@ -85,16 +102,18 @@ export function App() {
|
|
|
85
102
|
startRequest.current = controller
|
|
86
103
|
try {
|
|
87
104
|
const response = await client.start({ recipeId: recipe.id }, { signal: controller.signal, timeoutMs: START_TIMEOUT_MS })
|
|
88
|
-
if (!response.accepted)
|
|
105
|
+
if (!response.accepted) reportError("Start refused", response.message)
|
|
89
106
|
} catch (error) {
|
|
90
|
-
|
|
107
|
+
reportError("Start not confirmed", `${errorText(error)}. Check the station state before starting again.`)
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
const stop = () => {
|
|
95
|
-
client
|
|
96
|
-
|
|
97
|
-
.
|
|
112
|
+
client.trigger_Stop({}).catch((error: unknown) => {
|
|
113
|
+
const detail = errorText(error)
|
|
114
|
+
stopFailureIds.current.add(addEntry("error", "Stop did not reach the station", `${detail}. Use the emergency stop.`))
|
|
115
|
+
setStopFailure(`Stop did not reach the station (${detail}). Use the emergency stop.`)
|
|
116
|
+
})
|
|
98
117
|
}
|
|
99
118
|
|
|
100
119
|
return (
|
|
@@ -127,47 +146,64 @@ export function App() {
|
|
|
127
146
|
},
|
|
128
147
|
]}
|
|
129
148
|
/>
|
|
149
|
+
{/* Alerts float over the page, so one appearing never moves the page; the gaps between them stay tappable. */}
|
|
150
|
+
<Box
|
|
151
|
+
sx={{
|
|
152
|
+
position: "absolute",
|
|
153
|
+
top: "100%",
|
|
154
|
+
left: 0,
|
|
155
|
+
right: 0,
|
|
156
|
+
padding: 4,
|
|
157
|
+
display: "flex",
|
|
158
|
+
flexDirection: "column",
|
|
159
|
+
gap: 2,
|
|
160
|
+
pointerEvents: "none",
|
|
161
|
+
"& > *": { pointerEvents: "auto" },
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
{status === undefined && (
|
|
165
|
+
<VentionAlert
|
|
166
|
+
severity="warn"
|
|
167
|
+
size="xx-large"
|
|
168
|
+
title="Not connected to the app yet"
|
|
169
|
+
descriptionText="Stop is available once the app answers. Use the emergency stop if the machine moves."
|
|
170
|
+
isFullWidth
|
|
171
|
+
appearance="elevated"
|
|
172
|
+
/>
|
|
173
|
+
)}
|
|
174
|
+
{errorEntry !== undefined && (
|
|
175
|
+
<VentionAlert
|
|
176
|
+
severity="error"
|
|
177
|
+
size="xx-large"
|
|
178
|
+
title={errorEntry.message}
|
|
179
|
+
primaryButtonText="View"
|
|
180
|
+
onPrimaryButtonClick={viewError}
|
|
181
|
+
isFullWidth
|
|
182
|
+
appearance="elevated"
|
|
183
|
+
isCloseable
|
|
184
|
+
onCloseButtonClick={() => setErrorEntry(undefined)}
|
|
185
|
+
/>
|
|
186
|
+
)}
|
|
187
|
+
{stopFailure !== "" && (
|
|
188
|
+
<VentionAlert
|
|
189
|
+
severity="error"
|
|
190
|
+
size="xx-large"
|
|
191
|
+
title={stopFailure}
|
|
192
|
+
isFullWidth
|
|
193
|
+
appearance="elevated"
|
|
194
|
+
isCloseable
|
|
195
|
+
onCloseButtonClick={() => setStopFailure("")}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
</Box>
|
|
130
199
|
</Box>
|
|
131
|
-
{status === undefined && (
|
|
132
|
-
<VentionAlert
|
|
133
|
-
severity="warn"
|
|
134
|
-
size="xx-large"
|
|
135
|
-
title="Not connected to the app yet"
|
|
136
|
-
descriptionText="Stop is available once the app answers. Use the emergency stop if the machine moves."
|
|
137
|
-
isFullWidth
|
|
138
|
-
/>
|
|
139
|
-
)}
|
|
140
|
-
{errorEntry !== undefined && (
|
|
141
|
-
<VentionAlert
|
|
142
|
-
severity="error"
|
|
143
|
-
size="xx-large"
|
|
144
|
-
title={errorEntry.message}
|
|
145
|
-
primaryButtonText="View"
|
|
146
|
-
onPrimaryButtonClick={viewError}
|
|
147
|
-
isFullWidth
|
|
148
|
-
isCloseable
|
|
149
|
-
onCloseButtonClick={() => setErrorEntry(undefined)}
|
|
150
|
-
/>
|
|
151
|
-
)}
|
|
152
|
-
{commandError !== "" && (
|
|
153
|
-
<VentionAlert
|
|
154
|
-
severity="error"
|
|
155
|
-
size="xx-large"
|
|
156
|
-
title={commandError}
|
|
157
|
-
isFullWidth
|
|
158
|
-
isCloseable
|
|
159
|
-
onCloseButtonClick={() => setCommandError("")}
|
|
160
|
-
/>
|
|
161
|
-
)}
|
|
162
200
|
<Box sx={{ flex: 1, minHeight: 0, overflow: "auto", padding: 6 }}>
|
|
163
201
|
<Routes>
|
|
164
202
|
<Route
|
|
165
203
|
path="/"
|
|
166
|
-
element={
|
|
167
|
-
<OperatePage status={status} connected={connected} recipe={recipe} onRecipeChange={setRecipe} onError={setCommandError} />
|
|
168
|
-
}
|
|
204
|
+
element={<OperatePage status={status} connected={connected} recipe={recipe} onRecipeChange={setRecipe} onError={reportError} />}
|
|
169
205
|
/>
|
|
170
|
-
<Route path="/recipes" element={<RecipesPage connected={connected} onError={
|
|
206
|
+
<Route path="/recipes" element={<RecipesPage connected={connected} onError={reportError} />} />
|
|
171
207
|
<Route path="/logs" element={<LogsPage entries={logEntries} openEntry={openLogEntry} onOpenEntry={setOpenLogEntry} />} />
|
|
172
208
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
173
209
|
</Routes>
|
|
@@ -175,7 +211,22 @@ export function App() {
|
|
|
175
211
|
<NavigationBar variant="flex">
|
|
176
212
|
<NavigationBar.Item id="operate" label="Operate" path="/" icon={<IconLayoutDashboard size={NAV_ICON_SIZE} color="white" />} />
|
|
177
213
|
<NavigationBar.Item id="recipes" label="Recipes" path="/recipes" icon={<IconBook size={NAV_ICON_SIZE} color="white" />} />
|
|
178
|
-
<NavigationBar.Item
|
|
214
|
+
<NavigationBar.Item
|
|
215
|
+
id="logs"
|
|
216
|
+
label="Logs"
|
|
217
|
+
path="/logs"
|
|
218
|
+
icon={
|
|
219
|
+
// NavigationBar.Item has no badge, so the unread count sits on the icon's corner.
|
|
220
|
+
<Box sx={{ position: "relative", display: "flex" }}>
|
|
221
|
+
<IconHistory size={NAV_ICON_SIZE} color="white" />
|
|
222
|
+
{unseenErrors > 0 && (
|
|
223
|
+
<Box sx={{ position: "absolute", top: -8, right: -12 }}>
|
|
224
|
+
<VentionCounter color="red" variant="filled" size="large" value={unseenErrors} />
|
|
225
|
+
</Box>
|
|
226
|
+
)}
|
|
227
|
+
</Box>
|
|
228
|
+
}
|
|
229
|
+
/>
|
|
179
230
|
</NavigationBar>
|
|
180
231
|
<VentionModal
|
|
181
232
|
isOpen={confirmingStart && startable}
|
|
@@ -10,7 +10,7 @@ interface OperatePageProps {
|
|
|
10
10
|
connected: boolean
|
|
11
11
|
recipe: Recipe | undefined
|
|
12
12
|
onRecipeChange: (recipe: Recipe | undefined) => void
|
|
13
|
-
onError: (message: string) => void
|
|
13
|
+
onError: (message: string, detail: string) => void
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/** What the page shows. The same regions render in every phase; only their content changes. */
|
|
@@ -202,12 +202,12 @@ export function OperatePage({ status, connected, recipe, onRecipeChange, onError
|
|
|
202
202
|
if (!connected) return
|
|
203
203
|
client.recipe_ListRecords({}).then(
|
|
204
204
|
response => setRecipes(response.records),
|
|
205
|
-
(error: unknown) => onError(
|
|
205
|
+
(error: unknown) => onError("Could not load recipes", errorText(error))
|
|
206
206
|
)
|
|
207
207
|
}, [connected, onError])
|
|
208
208
|
|
|
209
209
|
const reset = () => {
|
|
210
|
-
client.trigger_Reset({}).catch((error: unknown) => onError(
|
|
210
|
+
client.trigger_Reset({}).catch((error: unknown) => onError("Reset failed", errorText(error)))
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
return (
|
|
@@ -19,7 +19,7 @@ const NUMERIC_FIELDS: { field: NumericField; label: string; unit: string; step:
|
|
|
19
19
|
|
|
20
20
|
interface RecipesPageProps {
|
|
21
21
|
connected: boolean
|
|
22
|
-
onError: (message: string) => void
|
|
22
|
+
onError: (message: string, detail: string) => void
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export function RecipesPage({ connected, onError }: RecipesPageProps) {
|
|
@@ -32,7 +32,7 @@ export function RecipesPage({ connected, onError }: RecipesPageProps) {
|
|
|
32
32
|
try {
|
|
33
33
|
setRecipes((await client.recipe_ListRecords({})).records)
|
|
34
34
|
} catch (error) {
|
|
35
|
-
onError(
|
|
35
|
+
onError("Could not load recipes", errorText(error))
|
|
36
36
|
}
|
|
37
37
|
}, [onError])
|
|
38
38
|
|
|
@@ -54,7 +54,7 @@ export function RecipesPage({ connected, onError }: RecipesPageProps) {
|
|
|
54
54
|
setEditingId(response.record?.id)
|
|
55
55
|
await reload()
|
|
56
56
|
} catch (error) {
|
|
57
|
-
onError(`Could not save ${draft.name}
|
|
57
|
+
onError(`Could not save ${draft.name}`, errorText(error))
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -66,7 +66,7 @@ export function RecipesPage({ connected, onError }: RecipesPageProps) {
|
|
|
66
66
|
edit(undefined)
|
|
67
67
|
await reload()
|
|
68
68
|
} catch (error) {
|
|
69
|
-
onError(`Could not delete ${draft.name}
|
|
69
|
+
onError(`Could not delete ${draft.name}`, errorText(error))
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -3,7 +3,7 @@ name: vention-monitoring
|
|
|
3
3
|
description: Diagnose deployed Vention machines from controller state, history, health, and activity data. Use when the user reports a machine that is down, faulted, offline, slow, or underperforming, asks why a cycle time regressed, wants to interpret MachineMotion event data or drive and brake status, asks about OEE or uptime, or wants to know which machine in a fleet needs attention. Trigger on a MachineMotion serial number plus any complaint.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.10.
|
|
6
|
+
version: "0.10.16"
|
|
7
7
|
author: Vention
|
|
8
8
|
---
|
|
9
9
|
|