@aryacode/dsh-engineering 0.4.6 → 0.4.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.7] - 2026-10-25
4
+
5
+ ### Fixed
6
+
7
+ - **`allowWrites` could not be reached from the L5X row.** The composite entry mounted the live entry
8
+ with no config, so the write switch had no path from the Plugins page. `entries/l5x.js` now declares
9
+ `allowWrites` and `allowedAddresses` and forwards both into the live entry; the write tools still
10
+ refuse without per-call approval.
11
+
12
+ ### Documentation
13
+
14
+ - README: the safety section states the two keys a live write takes, the tool groups list all seven
15
+ EtherNet/IP tools, and the L5X count is 40 (84 with Optix).
16
+ - `docs/examples.md`: a live section covering batch reads, discovery, the controller clock, the trend,
17
+ and a supervised write with the exact fields the reader must see and the refusals they may hit.
18
+ - `docs/architecture.md`: a new EtherNet/IP section — the two workers, the transaction engine's deadline
19
+ and decoding, and the four gates that stand between a write request and a controller.
20
+ - `docs/port/l5x.md`: the live surface is recorded as seven tools with the driver call each one uses, and
21
+ the unused capability (CIP subscriptions, UDT `Structure` reads) is named.
22
+ - `packages/l5x/README.md`: read and write tool tables, and the full live configuration row.
23
+
3
24
  ## [0.4.6] - 2026-10-25
4
25
 
5
26
  ### Added
package/README.md CHANGED
@@ -176,6 +176,9 @@ even when the implementation behind a row is replaced.
176
176
  - **Controller changes need a human.** Upload, mode change and download require per-call approval and
177
177
  a session policy that permits asking. The tools refuse before contacting a controller when approval
178
178
  is unavailable, and a download accepts only a verification id produced by a passed build.
179
+ - **Live writes take two keys.** `write_live_tag` and `write_controller_clock` need the row's
180
+ `allowWrites` switch *and* approval for that exact write; the tag is validated against the export
181
+ first and the result is the value the controller reads back (`WRITE_NOT_VERIFIED` if it differs).
179
182
  - **No hidden vendor execution.** The FactoryTalk View Studio handoff returns a manual import plan; it
180
183
  does not run a vendor utility.
181
184
  - **Coverage is stated.** Every result names what it cannot establish, including whether online logic
package/entries/l5x.js CHANGED
@@ -2,10 +2,14 @@
2
2
  * The Studio 5000 L5X product row: one switch for the whole L5X surface.
3
3
  *
4
4
  * The parts are the vendored entries; this module mounts them, so the Plugins
5
- * page shows one row per product instead of one per surface. The three
6
- * expensive surfaces stay off by default and are switched from this row's
7
- * config form, which is the same decision the old separate rows encoded —
8
- * just reachable from the product row instead of from the list.
5
+ * page shows one row per product instead of one per surface. The expensive
6
+ * surfaces stay off by default and are switched from this row's config form,
7
+ * which is the same decision the old separate rows encoded — just reachable
8
+ * from the product row instead of from the list.
9
+ *
10
+ * `allowWrites` is forwarded into the live entry, not consumed here: the write
11
+ * tools refuse from inside that entry, so the switch and the per-call approval
12
+ * both live where the controller traffic happens.
9
13
  */
10
14
  import z from '@deepseek-ai/schemastery'
11
15
  import * as read from '../vendor/l5x/lib/index.js'
@@ -26,19 +30,31 @@ export const Config = z.object({
26
30
  'Logix Designer SDK and supervised controller tools. Needs Studio 5000 with the SDK service installed.',
27
31
  ),
28
32
  live: z.boolean().default(false).description(
29
- 'EtherNet/IP polling and trend tools. Needs a reachable controller address.',
33
+ 'EtherNet/IP surface: polling, batch reads, discovery, controller clock and trends. Needs a reachable controller address.',
34
+ ),
35
+ allowWrites: z.boolean().default(false).description(
36
+ 'Permit the two live write tools (tag, wall clock). Each write still needs human approval for that exact operation, and only applies while live is on.',
37
+ ),
38
+ allowedAddresses: z.array(z.string()).default([]).description(
39
+ 'Optional IPv4 allowlist for live reads, writes and discovery. Empty permits any explicit address.',
30
40
  ),
31
41
  })
32
42
 
33
43
  /**
34
44
  * Mount the L5X surface.
35
45
  * @param ctx - plugin context.
36
- * @param config - the three optional surfaces, all off unless enabled.
46
+ * @param config - the optional surfaces, all off unless enabled.
37
47
  */
38
48
  export function apply(ctx, config = {}) {
39
49
  ctx.plugin(read)
40
50
  ctx.plugin(skill)
41
51
  if (config.editing === true) ctx.plugin(editing)
42
52
  if (config.studio === true) ctx.plugin(studio)
43
- if (config.live === true) ctx.plugin(live)
53
+ if (config.live === true) {
54
+ const addresses = Array.isArray(config.allowedAddresses) ? config.allowedAddresses : []
55
+ ctx.plugin(live, {
56
+ allowWrites: config.allowWrites === true,
57
+ ...(addresses.length === 0 ? {} : { allowedAddresses: addresses }),
58
+ })
59
+ }
44
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aryacode/dsh-engineering",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "description": "AryaCode engineering bundle: one install surface for the Studio 5000 L5X, FactoryTalk View ME, MotionWorks IEC and FactoryTalk Optix surfaces, one row per product, with the ladder and display previews.",
5
5
  "keywords": [
6
6
  "dsh",
@@ -7,7 +7,7 @@ Studio 5000 L5X tools for the `dsh-engineering` bundle. Four loader entries shar
7
7
  | `dsh-engineering-l5x` | 11 offline read and reference tools | Node |
8
8
  | `dsh-engineering-l5x/editing` | 9 `draft_*` tools | the read entry |
9
9
  | `dsh-engineering-l5x/studio` | 6 Logix Designer SDK tools and 7 supervised controller tools | Studio 5000, Logix Designer SDK, FactoryTalk Linx |
10
- | `dsh-engineering-l5x/live` | `poll_live_tags`, `start_plc_trend` | a reachable controller |
10
+ | `dsh-engineering-l5x/live` | 7 EtherNet/IP tools: `poll_live_tags`, `read_live_tags`, `read_controller_clock`, `discover_controllers`, `start_plc_trend`, and the approval-gated `write_live_tag`, `write_controller_clock` | a reachable controller for reads; the row's `allowWrites` plus human approval for writes |
11
11
 
12
12
  The `rockwell-l5x` guidance ships as the separate `dsh-engineering-l5x/skill` entry, and the PLC
13
13
  trend card ships as the client face (`dsh.client`).
@@ -40,9 +40,31 @@ operation is an upload, mode change or download; those require per-call human ap
40
40
 
41
41
  ## Live
42
42
 
43
- `poll_live_tags` and `start_plc_trend` read declared scalar tags over EtherNet/IP without Studio,
44
- Linx, an ACD or the SDK. They are read-only and report that live logic matching the export is
45
- unverified.
43
+ Reads need no approval and no Studio, Linx, ACD or SDK:
44
+
45
+ | Tool | What it does |
46
+ |---|---|
47
+ | `poll_live_tags` | Timed sweeps of 1–16 declared scalar tags, with quality and controller identity |
48
+ | `read_live_tags` | Up to 64 declared scalars in **one** request (CIP tag group) |
49
+ | `read_controller_clock` | Identity plus the wall clock beside the workstation clock and their offset (L8x) |
50
+ | `discover_controllers` | Bounded UDP broadcast discovery of EtherNet/IP devices on the LAN |
51
+ | `start_plc_trend` | Session-owned trend job the chart follows without a model call per sample |
52
+
53
+ Two writes exist and are **supervised**, not merely available:
54
+
55
+ | Tool | What it changes |
56
+ |---|---|
57
+ | `write_live_tag` | One declared scalar, then read back over CIP |
58
+ | `write_controller_clock` | The controller wall clock (L8x), then read back |
59
+
60
+ A write needs the row's `allowWrites` switch **and** a human approving that exact operation: with
61
+ `allowWrites` on and a `never` policy the tool refuses with `APPROVAL_UNAVAILABLE` before opening a
62
+ socket, and a declined prompt is `APPROVAL_DENIED`. Each write is validated against the open export
63
+ (declared, non-alias, no array dimensions, `ExternalAccess` not `None`, value inside the declared
64
+ type and range) and a readback that differs fails with `WRITE_NOT_VERIFIED`.
65
+
66
+ Every read reports that live logic matching the export is unverified, and sequential reads can miss
67
+ transitions between sweeps.
46
68
 
47
69
  ## Configuration
48
70
 
@@ -51,7 +73,7 @@ unverified.
51
73
  | read | `maxFileBytes` | 64 MiB |
52
74
  | editing | `maxFileBytes`, `maxDraftOperations` | 64 MiB, 200 |
53
75
  | studio | `maxFileBytes` | 64 MiB |
54
- | live | `enabled`, `minIntervalMs`, `defaultIntervalMs`, `maxTags`, `maxSamples` | true, 50 ms, 200 ms, 16, 1200 |
76
+ | live | `enabled`, `minIntervalMs`, `defaultIntervalMs`, `maxTags`, `maxSamples`, `allowWrites`, `maxBatchTags`, `allowedAddresses` | true, 50 ms, 200 ms, 16, 1200, false, 64, empty |
55
77
 
56
78
  ## Develop
57
79