@aryacode/dsh-engineering 0.0.0-stage → 0.4.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/CHANGELOG.md +128 -0
- package/LICENSE +21 -0
- package/README.md +230 -2
- package/cordis.patch.yml +123 -0
- package/lib/client.js +3448 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +9 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +94 -3
- package/vendor/ftview/README.md +55 -0
- package/vendor/ftview/SKILL.md +74 -0
- package/vendor/ftview/lib/checks.d.ts +27 -0
- package/vendor/ftview/lib/checks.js +39 -0
- package/vendor/ftview/lib/core.d.ts +208 -0
- package/vendor/ftview/lib/core.js +160 -0
- package/vendor/ftview/lib/edit/drafts.d.ts +49 -0
- package/vendor/ftview/lib/edit/drafts.js +84 -0
- package/vendor/ftview/lib/edit/operations.d.ts +62 -0
- package/vendor/ftview/lib/edit/operations.js +126 -0
- package/vendor/ftview/lib/edit/prepare.d.ts +38 -0
- package/vendor/ftview/lib/edit/prepare.js +133 -0
- package/vendor/ftview/lib/edit/tools.d.ts +25 -0
- package/vendor/ftview/lib/edit/tools.js +198 -0
- package/vendor/ftview/lib/edit.d.ts +30 -0
- package/vendor/ftview/lib/edit.js +38 -0
- package/vendor/ftview/lib/index.d.ts +31 -0
- package/vendor/ftview/lib/index.js +36 -0
- package/vendor/ftview/lib/model.d.ts +80 -0
- package/vendor/ftview/lib/model.js +267 -0
- package/vendor/ftview/lib/session.d.ts +48 -0
- package/vendor/ftview/lib/session.js +98 -0
- package/vendor/ftview/lib/skill.d.ts +29 -0
- package/vendor/ftview/lib/skill.js +43 -0
- package/vendor/ftview/lib/studio/discover.d.ts +36 -0
- package/vendor/ftview/lib/studio/discover.js +87 -0
- package/vendor/ftview/lib/studio/preflight.d.ts +51 -0
- package/vendor/ftview/lib/studio/preflight.js +64 -0
- package/vendor/ftview/lib/studio/tools.d.ts +15 -0
- package/vendor/ftview/lib/studio/tools.js +83 -0
- package/vendor/ftview/lib/studio.d.ts +30 -0
- package/vendor/ftview/lib/studio.js +37 -0
- package/vendor/ftview/lib/tools.d.ts +14 -0
- package/vendor/ftview/lib/tools.js +202 -0
- package/vendor/l5x/README.md +62 -0
- package/vendor/l5x/SKILL.md +81 -0
- package/vendor/l5x/lib/approvals.d.ts +50 -0
- package/vendor/l5x/lib/approvals.js +93 -0
- package/vendor/l5x/lib/client.js +412 -0
- package/vendor/l5x/lib/client.js.map +1 -0
- package/vendor/l5x/lib/core/errors.d.ts +38 -0
- package/vendor/l5x/lib/core/errors.js +48 -0
- package/vendor/l5x/lib/core/params.d.ts +49 -0
- package/vendor/l5x/lib/core/params.js +39 -0
- package/vendor/l5x/lib/core/result.d.ts +46 -0
- package/vendor/l5x/lib/core/result.js +21 -0
- package/vendor/l5x/lib/core/tool.d.ts +102 -0
- package/vendor/l5x/lib/core/tool.js +19 -0
- package/vendor/l5x/lib/drafts.d.ts +66 -0
- package/vendor/l5x/lib/drafts.js +98 -0
- package/vendor/l5x/lib/editing.d.ts +30 -0
- package/vendor/l5x/lib/editing.js +42 -0
- package/vendor/l5x/lib/engine/acd-edit.d.ts +13 -0
- package/vendor/l5x/lib/engine/acd-edit.js +115 -0
- package/vendor/l5x/lib/engine/analysis.d.ts +22 -0
- package/vendor/l5x/lib/engine/analysis.js +258 -0
- package/vendor/l5x/lib/engine/capabilities.d.ts +9 -0
- package/vendor/l5x/lib/engine/capabilities.js +40 -0
- package/vendor/l5x/lib/engine/change-set.d.ts +122 -0
- package/vendor/l5x/lib/engine/change-set.js +446 -0
- package/vendor/l5x/lib/engine/configuration.d.ts +21 -0
- package/vendor/l5x/lib/engine/configuration.js +42 -0
- package/vendor/l5x/lib/engine/details.d.ts +47 -0
- package/vendor/l5x/lib/engine/details.js +173 -0
- package/vendor/l5x/lib/engine/direct-polling.d.ts +91 -0
- package/vendor/l5x/lib/engine/direct-polling.js +193 -0
- package/vendor/l5x/lib/engine/download-review.d.ts +15 -0
- package/vendor/l5x/lib/engine/download-review.js +63 -0
- package/vendor/l5x/lib/engine/logic-syntax.d.ts +60 -0
- package/vendor/l5x/lib/engine/logic-syntax.js +237 -0
- package/vendor/l5x/lib/engine/observations.d.ts +41 -0
- package/vendor/l5x/lib/engine/observations.js +67 -0
- package/vendor/l5x/lib/engine/project-analysis.d.ts +131 -0
- package/vendor/l5x/lib/engine/project-analysis.js +314 -0
- package/vendor/l5x/lib/engine/review-evidence.d.ts +8 -0
- package/vendor/l5x/lib/engine/review-evidence.js +49 -0
- package/vendor/l5x/lib/engine/review.d.ts +18 -0
- package/vendor/l5x/lib/engine/review.js +123 -0
- package/vendor/l5x/lib/engine/studio-sdk.d.ts +101 -0
- package/vendor/l5x/lib/engine/studio-sdk.js +571 -0
- package/vendor/l5x/lib/engine/tag-resolution.d.ts +20 -0
- package/vendor/l5x/lib/engine/tag-resolution.js +169 -0
- package/vendor/l5x/lib/engine/usage.d.ts +16 -0
- package/vendor/l5x/lib/engine/usage.js +92 -0
- package/vendor/l5x/lib/engine/xml-regions.d.ts +23 -0
- package/vendor/l5x/lib/engine/xml-regions.js +77 -0
- package/vendor/l5x/lib/fs.d.ts +17 -0
- package/vendor/l5x/lib/fs.js +36 -0
- package/vendor/l5x/lib/index.d.ts +36 -0
- package/vendor/l5x/lib/index.js +42 -0
- package/vendor/l5x/lib/live.d.ts +48 -0
- package/vendor/l5x/lib/live.js +48 -0
- package/vendor/l5x/lib/model/aois.d.ts +39 -0
- package/vendor/l5x/lib/model/aois.js +112 -0
- package/vendor/l5x/lib/model/errors.d.ts +15 -0
- package/vendor/l5x/lib/model/errors.js +18 -0
- package/vendor/l5x/lib/model/index.d.ts +20 -0
- package/vendor/l5x/lib/model/index.js +19 -0
- package/vendor/l5x/lib/model/module.d.ts +37 -0
- package/vendor/l5x/lib/model/module.js +54 -0
- package/vendor/l5x/lib/model/modules.d.ts +24 -0
- package/vendor/l5x/lib/model/modules.js +55 -0
- package/vendor/l5x/lib/model/parse.d.ts +32 -0
- package/vendor/l5x/lib/model/parse.js +116 -0
- package/vendor/l5x/lib/model/project.d.ts +15 -0
- package/vendor/l5x/lib/model/project.js +31 -0
- package/vendor/l5x/lib/model/routines.d.ts +71 -0
- package/vendor/l5x/lib/model/routines.js +183 -0
- package/vendor/l5x/lib/model/tags.d.ts +51 -0
- package/vendor/l5x/lib/model/tags.js +119 -0
- package/vendor/l5x/lib/model/types.d.ts +304 -0
- package/vendor/l5x/lib/model/types.js +12 -0
- package/vendor/l5x/lib/model/udts.d.ts +34 -0
- package/vendor/l5x/lib/model/udts.js +81 -0
- package/vendor/l5x/lib/model/xml.d.ts +139 -0
- package/vendor/l5x/lib/model/xml.js +291 -0
- package/vendor/l5x/lib/model/xref.d.ts +28 -0
- package/vendor/l5x/lib/model/xref.js +154 -0
- package/vendor/l5x/lib/session.d.ts +119 -0
- package/vendor/l5x/lib/session.js +236 -0
- package/vendor/l5x/lib/skill.d.ts +30 -0
- package/vendor/l5x/lib/skill.js +44 -0
- package/vendor/l5x/lib/studio-state.d.ts +77 -0
- package/vendor/l5x/lib/studio-state.js +79 -0
- package/vendor/l5x/lib/studio.d.ts +29 -0
- package/vendor/l5x/lib/studio.js +40 -0
- package/vendor/l5x/lib/tools/checks.d.ts +19 -0
- package/vendor/l5x/lib/tools/checks.js +140 -0
- package/vendor/l5x/lib/tools/common.d.ts +41 -0
- package/vendor/l5x/lib/tools/common.js +84 -0
- package/vendor/l5x/lib/tools/controller.d.ts +21 -0
- package/vendor/l5x/lib/tools/controller.js +170 -0
- package/vendor/l5x/lib/tools/drafts.d.ts +23 -0
- package/vendor/l5x/lib/tools/drafts.js +270 -0
- package/vendor/l5x/lib/tools/live.d.ts +21 -0
- package/vendor/l5x/lib/tools/live.js +175 -0
- package/vendor/l5x/lib/tools/read.d.ts +19 -0
- package/vendor/l5x/lib/tools/read.js +245 -0
- package/vendor/l5x/lib/tools/references.d.ts +20 -0
- package/vendor/l5x/lib/tools/references.js +269 -0
- package/vendor/l5x/lib/tools/studio.d.ts +21 -0
- package/vendor/l5x/lib/tools/studio.js +193 -0
- package/vendor/l5x/poll-worker.mjs +77 -0
- package/vendor/l5x/studio-bridge/NuGet.Config +1 -0
- package/vendor/l5x/studio-bridge/Program.cs +304 -0
- package/vendor/l5x/studio-bridge/StudioBridge.csproj +11 -0
- package/vendor/mwi/README.md +60 -0
- package/vendor/mwi/SKILL.md +87 -0
- package/vendor/mwi/bridge/README.md +8 -0
- package/vendor/mwi/bridge/mw_bridge.ps1 +2763 -0
- package/vendor/mwi/bridge/sdk-interop-importer.cs +30 -0
- package/vendor/mwi/bridge/sdk-variable-reader.cs +22 -0
- package/vendor/mwi/bridge/start_bridge.cmd +21 -0
- package/vendor/mwi/bridge/watch_dialogs.cmd +13 -0
- package/vendor/mwi/bridge/watch_dialogs.ps1 +153 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__init__.py +14 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/__init__.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/block_interfaces.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/cfb.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/datatypes.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/declarations.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/errors.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/graphical_listing.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/grid.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/knowledge.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/mwt_bind.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/navigation.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/program_checks.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/project.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/staging.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/structure.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/task_bindings.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/tasks.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/tree.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/validation.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/variable_edit.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/variables.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/__pycache__/workflow.cpython-312.pyc +0 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/block_interfaces.py +275 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/build.py +339 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/capture.py +448 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/cfb.py +765 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/com.py +268 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/datatypes.py +204 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/declarations.py +399 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/descriptions.py +30 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/eip.py +292 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/errors.py +36 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/graphical_listing.py +208 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/grid.py +227 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/ide.py +317 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/iec.py +317 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/installed_help.py +151 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/knowledge.py +218 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/libraries.py +250 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/manuals.py +520 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/mwt_bind.py +133 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/navigation.py +44 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/pou_writer.py +1547 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/program_checks.py +360 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/project.py +704 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/reference_data/catalog.json +672 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/reference_data/patterns.json +86 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/restore.py +208 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/server.py +1913 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/snapshot.py +138 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/st_comments.py +25 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/staging.py +179 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/stlint.py +676 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/structure.py +98 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/task_bindings.py +68 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tasks.py +162 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/transaction.py +157 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tree.py +563 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/tree_writer.py +790 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/uia.py +465 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/validation.py +41 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/variable_edit.py +183 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/variables.py +472 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/workflow.py +130 -0
- package/vendor/mwi/code/engine/motionworks_iec_mcp/writer.py +666 -0
- package/vendor/mwi/code/mw_code.py +1258 -0
- package/vendor/mwi/legacy/edit-session.js +50 -0
- package/vendor/mwi/legacy/fb-insertion.js +74 -0
- package/vendor/mwi/legacy/native-code.js +83 -0
- package/vendor/mwi/legacy/native-groups.js +75 -0
- package/vendor/mwi/legacy/native-structure.js +143 -0
- package/vendor/mwi/legacy/native-variables.js +77 -0
- package/vendor/mwi/legacy/pou-conversion.js +47 -0
- package/vendor/mwi/legacy/pou-package.js +66 -0
- package/vendor/mwi/lib/core/bridge.d.ts +71 -0
- package/vendor/mwi/lib/core/bridge.js +53 -0
- package/vendor/mwi/lib/core/code-engine.d.ts +47 -0
- package/vendor/mwi/lib/core/code-engine.js +109 -0
- package/vendor/mwi/lib/core/errors.d.ts +37 -0
- package/vendor/mwi/lib/core/errors.js +47 -0
- package/vendor/mwi/lib/core/params.d.ts +52 -0
- package/vendor/mwi/lib/core/params.js +46 -0
- package/vendor/mwi/lib/core/ps-bridge.d.ts +62 -0
- package/vendor/mwi/lib/core/ps-bridge.js +127 -0
- package/vendor/mwi/lib/core/result.d.ts +45 -0
- package/vendor/mwi/lib/core/result.js +20 -0
- package/vendor/mwi/lib/core/tool.d.ts +80 -0
- package/vendor/mwi/lib/core/tool.js +55 -0
- package/vendor/mwi/lib/edit/compare.d.ts +33 -0
- package/vendor/mwi/lib/edit/compare.js +70 -0
- package/vendor/mwi/lib/edit.d.ts +20 -0
- package/vendor/mwi/lib/edit.js +32 -0
- package/vendor/mwi/lib/index.d.ts +21 -0
- package/vendor/mwi/lib/index.js +33 -0
- package/vendor/mwi/lib/read/service.d.ts +117 -0
- package/vendor/mwi/lib/read/service.js +229 -0
- package/vendor/mwi/lib/read.d.ts +21 -0
- package/vendor/mwi/lib/read.js +33 -0
- package/vendor/mwi/lib/session/project.d.ts +34 -0
- package/vendor/mwi/lib/session/project.js +54 -0
- package/vendor/mwi/lib/session/service.d.ts +167 -0
- package/vendor/mwi/lib/session/service.js +566 -0
- package/vendor/mwi/lib/session/stage.d.ts +84 -0
- package/vendor/mwi/lib/session/stage.js +187 -0
- package/vendor/mwi/lib/session/workspace.d.ts +52 -0
- package/vendor/mwi/lib/session/workspace.js +90 -0
- package/vendor/mwi/lib/skill.d.ts +36 -0
- package/vendor/mwi/lib/skill.js +56 -0
- package/vendor/mwi/lib/tools/edit.d.ts +20 -0
- package/vendor/mwi/lib/tools/edit.js +286 -0
- package/vendor/mwi/lib/tools/read.d.ts +19 -0
- package/vendor/mwi/lib/tools/read.js +161 -0
- package/vendor/mwi/lib/tools/session.d.ts +20 -0
- package/vendor/mwi/lib/tools/session.js +166 -0
- package/vendor/mwi/lib/tools/verify.d.ts +19 -0
- package/vendor/mwi/lib/tools/verify.js +85 -0
- package/vendor/mwi/lib/verify.d.ts +17 -0
- package/vendor/mwi/lib/verify.js +29 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The FTView editing tools: stage, validate, apply.
|
|
3
|
+
*
|
|
4
|
+
* One operation per call, accumulated per chat and export, validated against a
|
|
5
|
+
* re-parsed copy, then written to a new export folder. The source is never
|
|
6
|
+
* modified.
|
|
7
|
+
*
|
|
8
|
+
* @module dsh-engineering-ftview/edit/tools
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from 'node:crypto';
|
|
11
|
+
import { EngineeringError, object, optionalString, requiredString, string, success, tool } from "../core.js";
|
|
12
|
+
import { EDIT_COVERAGE, prepareEdit } from "./prepare.js";
|
|
13
|
+
/** The view handle parameter, described once. */
|
|
14
|
+
const VIEW_ID = string('View handle returned by ftview_open. Omit when exactly one export is open in this chat.');
|
|
15
|
+
/** The draft handle parameter, described once. */
|
|
16
|
+
const DRAFT_ID = string('Draft handle returned by an ftview_draft_* tool. Omit when exactly one draft exists in this chat.');
|
|
17
|
+
/** Coverage for apply, which writes text exports only. */
|
|
18
|
+
const APPLY_COVERAGE = {
|
|
19
|
+
...EDIT_COVERAGE,
|
|
20
|
+
unverified: [...EDIT_COVERAGE.unverified, 'files that are not display XML or tag CSV are not copied'],
|
|
21
|
+
};
|
|
22
|
+
/** The next step after staging an operation. */
|
|
23
|
+
function nextValidate(draftId) {
|
|
24
|
+
return [{ tool: 'ftview_validate', args: { draft_id: draftId }, why: 'Prepare the changed export and read the findings before writing anything.' }];
|
|
25
|
+
}
|
|
26
|
+
/** Count duplicate named objects in one display. */
|
|
27
|
+
function objectCount(display, name) {
|
|
28
|
+
return display.objects.filter(object => object.name === name).length;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The editing tools.
|
|
32
|
+
*
|
|
33
|
+
* @param session - View handles from the read entry.
|
|
34
|
+
* @param drafts - Draft store for the calling chat.
|
|
35
|
+
* @param fs - Filesystem provider used to read sources and write the result.
|
|
36
|
+
* @param maxOperations - Inclusive operations per draft.
|
|
37
|
+
* @returns Tool definitions in registration order.
|
|
38
|
+
*/
|
|
39
|
+
export function editTools(session, drafts, fs, maxOperations) {
|
|
40
|
+
/** Resolve the view and append one operation. */
|
|
41
|
+
const stage = (exec, viewId, operation) => {
|
|
42
|
+
const view = session.require(viewId, exec);
|
|
43
|
+
return { view, draft: drafts.append(exec, view.id, operation, maxOperations) };
|
|
44
|
+
};
|
|
45
|
+
const staged = (draft, operation) => success(`Draft ${draft.id}: ${draft.operations.length} ${draft.operations.length === 1 ? 'operation' : 'operations'}.`, { draft_id: draft.id, operation_count: draft.operations.length, last_operation: operation }, nextValidate(draft.id), EDIT_COVERAGE);
|
|
46
|
+
return [
|
|
47
|
+
tool({
|
|
48
|
+
name: 'ftview_draft_display_set',
|
|
49
|
+
description: 'Stage one attribute change on a display or on one of its named objects. Nothing is written until ftview_apply.',
|
|
50
|
+
parameters: object({
|
|
51
|
+
view_id: VIEW_ID,
|
|
52
|
+
display: string('Display name as listed by ftview_list. Example: "Main".'),
|
|
53
|
+
object: string('Object name inside the display. Omit to change the display root. Example: "StartPB".'),
|
|
54
|
+
attribute: string('Attribute to set. Example: "visible" or "caption".'),
|
|
55
|
+
value: string('New attribute value. Example: "0".'),
|
|
56
|
+
}, ['display', 'attribute', 'value']),
|
|
57
|
+
async run(args, exec) {
|
|
58
|
+
const view = session.require(optionalString(args, 'view_id'), exec);
|
|
59
|
+
const displayName = requiredString(args, 'display');
|
|
60
|
+
const display = view.app.displays.find(candidate => candidate.name === displayName);
|
|
61
|
+
if (display === undefined) {
|
|
62
|
+
throw new EngineeringError('COMPONENT_NOT_FOUND', `No display is named ${JSON.stringify(displayName)} in this export.`, 'Call ftview_list with kind "display" to see the display names.', view.app.displays.slice(0, 5).map(candidate => candidate.name));
|
|
63
|
+
}
|
|
64
|
+
const objectName = optionalString(args, 'object');
|
|
65
|
+
if (objectName !== undefined) {
|
|
66
|
+
const count = objectCount(display, objectName);
|
|
67
|
+
if (count === 0) {
|
|
68
|
+
throw new EngineeringError('COMPONENT_NOT_FOUND', `No object in ${JSON.stringify(display.name)} is named ${JSON.stringify(objectName)}.`, 'Call ftview_get with kind "display" to see the object names.', display.objects.flatMap(candidate => candidate.name === undefined ? [] : [candidate.name]).slice(0, 5));
|
|
69
|
+
}
|
|
70
|
+
if (count > 1) {
|
|
71
|
+
throw new EngineeringError('AMBIGUOUS_OBJECT', `${display.name} has ${count} objects named ${JSON.stringify(objectName)}, so the edit target is ambiguous.`, 'This export cannot be edited by name alone; use Studio for that display.');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const { draft } = stage(exec, optionalString(args, 'view_id'), {
|
|
75
|
+
kind: 'display_set',
|
|
76
|
+
file: display.file,
|
|
77
|
+
...(objectName === undefined ? {} : { object: objectName }),
|
|
78
|
+
attribute: requiredString(args, 'attribute'),
|
|
79
|
+
value: requiredString(args, 'value'),
|
|
80
|
+
});
|
|
81
|
+
return staged(draft, draft.operations[draft.operations.length - 1]);
|
|
82
|
+
},
|
|
83
|
+
}),
|
|
84
|
+
tool({
|
|
85
|
+
name: 'ftview_draft_display_add',
|
|
86
|
+
description: 'Stage a new display by copying an existing display file under a new name. Nothing is written until ftview_apply.',
|
|
87
|
+
parameters: object({
|
|
88
|
+
view_id: VIEW_ID,
|
|
89
|
+
copy_from: string('Display name to copy. Example: "Main".'),
|
|
90
|
+
name: string('New display name, unique in the export. Example: "MainCopy".'),
|
|
91
|
+
}, ['copy_from', 'name']),
|
|
92
|
+
async run(args, exec) {
|
|
93
|
+
const view = session.require(optionalString(args, 'view_id'), exec);
|
|
94
|
+
const copyFrom = requiredString(args, 'copy_from');
|
|
95
|
+
const name = requiredString(args, 'name');
|
|
96
|
+
if (!view.app.displays.some(display => display.name === copyFrom)) {
|
|
97
|
+
throw new EngineeringError('COMPONENT_NOT_FOUND', `No display is named ${JSON.stringify(copyFrom)} to copy.`, 'Call ftview_list with kind "display" to see the display names.', view.app.displays.slice(0, 5).map(display => display.name));
|
|
98
|
+
}
|
|
99
|
+
if (view.app.displays.some(display => display.name === name)) {
|
|
100
|
+
throw new EngineeringError('COMPONENT_EXISTS', `A display named ${JSON.stringify(name)} already exists in this export.`, 'Pass a new display name, for example "LineOverview2".');
|
|
101
|
+
}
|
|
102
|
+
const { draft } = stage(exec, optionalString(args, 'view_id'), {
|
|
103
|
+
kind: 'display_add',
|
|
104
|
+
copyFrom,
|
|
105
|
+
name,
|
|
106
|
+
});
|
|
107
|
+
return staged(draft, draft.operations[draft.operations.length - 1]);
|
|
108
|
+
},
|
|
109
|
+
}),
|
|
110
|
+
tool({
|
|
111
|
+
name: 'ftview_draft_tag_upsert',
|
|
112
|
+
description: 'Stage one HMI tag update: change an existing row\'s description or type, or append a new tag row. Nothing is written until ftview_apply.',
|
|
113
|
+
parameters: object({
|
|
114
|
+
view_id: VIEW_ID,
|
|
115
|
+
name: string('Tag name. Example: "StartPB".'),
|
|
116
|
+
description: string('New tag description. Example: "Start pushbutton".'),
|
|
117
|
+
type: string('New tag type. Example: "A" for analog or "D" for digital.'),
|
|
118
|
+
}, ['name']),
|
|
119
|
+
async run(args, exec) {
|
|
120
|
+
const description = optionalString(args, 'description');
|
|
121
|
+
const type = optionalString(args, 'type');
|
|
122
|
+
if (description === undefined && type === undefined) {
|
|
123
|
+
throw new EngineeringError('INVALID_ARGUMENT', 'A tag upsert needs a description, a type, or both.', 'Pass description, type, or both; for example "Start pushbutton".');
|
|
124
|
+
}
|
|
125
|
+
const { draft } = stage(exec, optionalString(args, 'view_id'), {
|
|
126
|
+
kind: 'tag_upsert',
|
|
127
|
+
name: requiredString(args, 'name'),
|
|
128
|
+
...(description === undefined ? {} : { description }),
|
|
129
|
+
...(type === undefined ? {} : { type }),
|
|
130
|
+
});
|
|
131
|
+
return staged(draft, draft.operations[draft.operations.length - 1]);
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
tool({
|
|
135
|
+
name: 'ftview_validate',
|
|
136
|
+
description: 'Prepare the staged edits: apply them to a re-parsed copy, report the changed files and the new structural findings. Writes nothing.',
|
|
137
|
+
parameters: object({ draft_id: DRAFT_ID }, []),
|
|
138
|
+
async run(args, exec) {
|
|
139
|
+
const draft = drafts.get(exec, optionalString(args, 'draft_id'));
|
|
140
|
+
const view = session.require(draft.viewId, exec);
|
|
141
|
+
const prepared = await prepareEdit(fs, view.app, draft.operations, exec.signal);
|
|
142
|
+
const byRule = {};
|
|
143
|
+
for (const finding of prepared.findings)
|
|
144
|
+
byRule[finding.rule] = (byRule[finding.rule] ?? 0) + 1;
|
|
145
|
+
return success(`${draft.operations.length} operation(s); ${prepared.texts.size} file(s) change; ${prepared.findings.length} finding(s).`, {
|
|
146
|
+
draft_id: draft.id,
|
|
147
|
+
draft_sha256: prepared.hash,
|
|
148
|
+
changed_files: [...prepared.texts.keys()],
|
|
149
|
+
added: prepared.added,
|
|
150
|
+
findings: prepared.findings,
|
|
151
|
+
by_rule: byRule,
|
|
152
|
+
}, [{ tool: 'ftview_apply', args: { draft_id: draft.id }, why: 'Write the prepared export to a new folder.' }], EDIT_COVERAGE);
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
tool({
|
|
156
|
+
name: 'ftview_apply',
|
|
157
|
+
description: 'Write the prepared edits to a NEW export folder: changed files get the edits, other text exports are copied verbatim. The source folder is never modified.',
|
|
158
|
+
parameters: object({
|
|
159
|
+
draft_id: DRAFT_ID,
|
|
160
|
+
output_root: string('New folder for the edited export. It must not exist. Example: "C:/Projects/Line/ME Export Edited".'),
|
|
161
|
+
}, ['output_root']),
|
|
162
|
+
async run(args, exec) {
|
|
163
|
+
const draft = drafts.get(exec, optionalString(args, 'draft_id'));
|
|
164
|
+
const view = session.require(draft.viewId, exec);
|
|
165
|
+
const prepared = await prepareEdit(fs, view.app, draft.operations, exec.signal);
|
|
166
|
+
const outputRoot = await fs.resolve(requiredString(args, 'output_root'), {
|
|
167
|
+
...(exec.cwd === undefined ? {} : { cwd: exec.cwd }),
|
|
168
|
+
...(exec.signal === undefined ? {} : { signal: exec.signal }),
|
|
169
|
+
});
|
|
170
|
+
const existing = await fs.stat(outputRoot, exec.signal);
|
|
171
|
+
if (existing !== undefined) {
|
|
172
|
+
throw new EngineeringError('OUTPUT_EXISTS', `A file or folder already exists at ${requiredString(args, 'output_root')}.`, 'Pass a new output_root; apply never merges into an existing folder.');
|
|
173
|
+
}
|
|
174
|
+
if (fs.writeText === undefined) {
|
|
175
|
+
throw new EngineeringError('OUTPUT_UNAVAILABLE', 'The filesystem provider in this profile cannot write files.', 'Use a profile whose filesystem provider allows writes.');
|
|
176
|
+
}
|
|
177
|
+
const hashes = new Map(view.app.files.map(file => [file.file, file.sha256]));
|
|
178
|
+
let written = 0;
|
|
179
|
+
for (const file of view.app.files) {
|
|
180
|
+
const bytes = await fs.readBytes(`${view.app.root}/${file.file}`, exec.signal, 64 * 1024 * 1024);
|
|
181
|
+
if (createHash('sha256').update(bytes).digest('hex') !== hashes.get(file.file)) {
|
|
182
|
+
throw new EngineeringError('STALE_EXPORT', `The export changed on disk since it was opened: ${file.file}.`, 'Reopen the export with ftview_open, stage the edits again, then apply.');
|
|
183
|
+
}
|
|
184
|
+
const text = prepared.texts.get(file.file) ?? new TextDecoder('utf-8').decode(bytes);
|
|
185
|
+
await fs.writeText(`${outputRoot}/${file.file}`, text, { kind: 'createIfAbsent' }, exec.signal);
|
|
186
|
+
written += 1;
|
|
187
|
+
}
|
|
188
|
+
for (const file of prepared.added) {
|
|
189
|
+
const text = prepared.texts.get(file);
|
|
190
|
+
await fs.writeText(`${outputRoot}/${file}`, text, { kind: 'createIfAbsent' }, exec.signal);
|
|
191
|
+
written += 1;
|
|
192
|
+
}
|
|
193
|
+
drafts.remove(exec, draft.id);
|
|
194
|
+
return success(`Wrote ${written} file(s) to ${outputRoot}.`, { output_root: outputRoot, draft_id: draft.id, files_written: written, changed_files: [...prepared.texts.keys()] }, [{ tool: 'ftview_open', args: { root: outputRoot }, why: 'Reopen the written export and check it.' }], APPLY_COVERAGE);
|
|
195
|
+
},
|
|
196
|
+
}),
|
|
197
|
+
];
|
|
198
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The L5X-style editing entry for FactoryTalk View ME: drafts over the read
|
|
3
|
+
* entry's opened views.
|
|
4
|
+
*
|
|
5
|
+
* Separate so a read-only profile does not pay for five edit schemas. It
|
|
6
|
+
* consumes the `ftviewViews` service the read entry provides, so an export is
|
|
7
|
+
* scanned once and both entries see the same handle.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-engineering-ftview/edit
|
|
10
|
+
*/
|
|
11
|
+
import { type PluginContext } from './core.ts';
|
|
12
|
+
/** Plugin name in a composition. */
|
|
13
|
+
export declare const name = "ftview-edit";
|
|
14
|
+
/** The read entry's view service must already be mounted. */
|
|
15
|
+
export declare const inject: readonly ["tools", "fs", "ftviewViews"];
|
|
16
|
+
/** Configuration for the editing entry. */
|
|
17
|
+
export interface Config {
|
|
18
|
+
/** Most operations one draft may accumulate. Defaults to 100. */
|
|
19
|
+
maxDraftOperations?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register the editing tools.
|
|
23
|
+
*
|
|
24
|
+
* @param ctx - Plugin context carrying the read entry's view service.
|
|
25
|
+
* @param config - Deployment limits.
|
|
26
|
+
*/
|
|
27
|
+
export declare function apply(ctx: PluginContext, config?: Config): void;
|
|
28
|
+
export { EditDrafts } from './edit/drafts.ts';
|
|
29
|
+
export { editTools } from './edit/tools.ts';
|
|
30
|
+
export { prepareEdit } from './edit/prepare.ts';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The L5X-style editing entry for FactoryTalk View ME: drafts over the read
|
|
3
|
+
* entry's opened views.
|
|
4
|
+
*
|
|
5
|
+
* Separate so a read-only profile does not pay for five edit schemas. It
|
|
6
|
+
* consumes the `ftviewViews` service the read entry provides, so an export is
|
|
7
|
+
* scanned once and both entries see the same handle.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-engineering-ftview/edit
|
|
10
|
+
*/
|
|
11
|
+
import { stringFs } from "./core.js";
|
|
12
|
+
import { EditDrafts } from "./edit/drafts.js";
|
|
13
|
+
import { editTools } from "./edit/tools.js";
|
|
14
|
+
/** Plugin name in a composition. */
|
|
15
|
+
export const name = 'ftview-edit';
|
|
16
|
+
/** The read entry's view service must already be mounted. */
|
|
17
|
+
export const inject = ['tools', 'fs', 'ftviewViews'];
|
|
18
|
+
/**
|
|
19
|
+
* Register the editing tools.
|
|
20
|
+
*
|
|
21
|
+
* @param ctx - Plugin context carrying the read entry's view service.
|
|
22
|
+
* @param config - Deployment limits.
|
|
23
|
+
*/
|
|
24
|
+
export function apply(ctx, config = {}) {
|
|
25
|
+
const session = ctx.get?.('ftviewViews');
|
|
26
|
+
if (session === undefined) {
|
|
27
|
+
throw new Error('ftview-edit: the ftviewViews service is unavailable; mount the FTView read entry before this one');
|
|
28
|
+
}
|
|
29
|
+
const maxDraftOperations = config.maxDraftOperations ?? 100;
|
|
30
|
+
if (!Number.isInteger(maxDraftOperations) || maxDraftOperations <= 0) {
|
|
31
|
+
throw new Error('ftview-edit: maxDraftOperations must be a positive integer');
|
|
32
|
+
}
|
|
33
|
+
for (const definition of editTools(session, new EditDrafts(), stringFs(ctx.fs), maxDraftOperations))
|
|
34
|
+
ctx.tools.register(definition);
|
|
35
|
+
}
|
|
36
|
+
export { EditDrafts } from "./edit/drafts.js";
|
|
37
|
+
export { editTools } from "./edit/tools.js";
|
|
38
|
+
export { prepareEdit } from "./edit/prepare.js";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rebuilt FactoryTalk View ME read surface.
|
|
3
|
+
*
|
|
4
|
+
* Six intents over one opened export folder: open, list, get, find, check and
|
|
5
|
+
* compare. No Python engine, no Studio automation, no MER decoding.
|
|
6
|
+
*
|
|
7
|
+
* @module dsh-engineering-ftview
|
|
8
|
+
*/
|
|
9
|
+
import { type PluginContext } from './core.ts';
|
|
10
|
+
/** Plugin name in a composition. */
|
|
11
|
+
export declare const name = "ftview-read";
|
|
12
|
+
/** Services this plugin cannot register without. */
|
|
13
|
+
export declare const inject: readonly ["tools", "fs"];
|
|
14
|
+
/** Service name the editing entry consumes. */
|
|
15
|
+
export declare const VIEWS_SERVICE = "ftviewViews";
|
|
16
|
+
/** Configuration for the read surface. */
|
|
17
|
+
export interface Config {
|
|
18
|
+
/** Most display and tag files one open may scan. Defaults to 2000. */
|
|
19
|
+
maxFiles?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register the ME read surface.
|
|
23
|
+
*
|
|
24
|
+
* @param ctx - Plugin context with the tool registry and filesystem provider.
|
|
25
|
+
* @param config - Deployment limits.
|
|
26
|
+
*/
|
|
27
|
+
export declare function apply(ctx: PluginContext, config?: Config): void;
|
|
28
|
+
export { ViewSession } from './session.ts';
|
|
29
|
+
export { ftviewTools } from './tools.ts';
|
|
30
|
+
export { EngineeringError } from './core.ts';
|
|
31
|
+
export type { Coverage, NextStep, Success, ToolDefinition } from './core.ts';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rebuilt FactoryTalk View ME read surface.
|
|
3
|
+
*
|
|
4
|
+
* Six intents over one opened export folder: open, list, get, find, check and
|
|
5
|
+
* compare. No Python engine, no Studio automation, no MER decoding.
|
|
6
|
+
*
|
|
7
|
+
* @module dsh-engineering-ftview
|
|
8
|
+
*/
|
|
9
|
+
import { stringFs } from "./core.js";
|
|
10
|
+
import { ViewSession } from "./session.js";
|
|
11
|
+
import { ftviewTools } from "./tools.js";
|
|
12
|
+
/** Plugin name in a composition. */
|
|
13
|
+
export const name = 'ftview-read';
|
|
14
|
+
/** Services this plugin cannot register without. */
|
|
15
|
+
export const inject = ['tools', 'fs'];
|
|
16
|
+
/** Service name the editing entry consumes. */
|
|
17
|
+
export const VIEWS_SERVICE = 'ftviewViews';
|
|
18
|
+
/**
|
|
19
|
+
* Register the ME read surface.
|
|
20
|
+
*
|
|
21
|
+
* @param ctx - Plugin context with the tool registry and filesystem provider.
|
|
22
|
+
* @param config - Deployment limits.
|
|
23
|
+
*/
|
|
24
|
+
export function apply(ctx, config = {}) {
|
|
25
|
+
const maxFiles = config.maxFiles ?? 2000;
|
|
26
|
+
if (!Number.isInteger(maxFiles) || maxFiles <= 0) {
|
|
27
|
+
throw new Error('ftview-read: maxFiles must be a positive integer');
|
|
28
|
+
}
|
|
29
|
+
const session = new ViewSession(stringFs(ctx.fs), maxFiles);
|
|
30
|
+
ctx.provide?.(VIEWS_SERVICE, session);
|
|
31
|
+
for (const definition of ftviewTools(session))
|
|
32
|
+
ctx.tools.register(definition);
|
|
33
|
+
}
|
|
34
|
+
export { ViewSession } from "./session.js";
|
|
35
|
+
export { ftviewTools } from "./tools.js";
|
|
36
|
+
export { EngineeringError } from "./core.js";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FactoryTalk View ME export scanning and parsing.
|
|
3
|
+
*
|
|
4
|
+
* Only documented text exports are read: display XML and the semicolon-separated
|
|
5
|
+
* HMI tag CSV. Native MER/MED databases are not decoded or rewritten. A display
|
|
6
|
+
* contributes its root identity and its named objects; the tag CSV contributes
|
|
7
|
+
* typed rows, and its structural problems are reported rather than hidden.
|
|
8
|
+
*
|
|
9
|
+
* @module dsh-engineering-ftview/model
|
|
10
|
+
*/
|
|
11
|
+
import { type FsService } from './core.ts';
|
|
12
|
+
/** One row of the HMI tag CSV, keyed by its canonical columns. */
|
|
13
|
+
export interface TagRow {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly description: string;
|
|
16
|
+
readonly type: string;
|
|
17
|
+
readonly raw: Readonly<Record<string, string>>;
|
|
18
|
+
}
|
|
19
|
+
/** One named object inside a display. */
|
|
20
|
+
export interface DisplayObject {
|
|
21
|
+
readonly type: string;
|
|
22
|
+
readonly name?: string;
|
|
23
|
+
readonly attributes: Readonly<Record<string, string>>;
|
|
24
|
+
}
|
|
25
|
+
/** One parsed display file. */
|
|
26
|
+
export interface DisplayFile {
|
|
27
|
+
readonly file: string;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly objects: readonly DisplayObject[];
|
|
30
|
+
readonly parseError?: string;
|
|
31
|
+
}
|
|
32
|
+
/** One file the scan read, with its content hash. */
|
|
33
|
+
export interface ScannedFile {
|
|
34
|
+
readonly file: string;
|
|
35
|
+
readonly bytes: number;
|
|
36
|
+
readonly sha256: string;
|
|
37
|
+
}
|
|
38
|
+
/** One export folder, scanned once and read by every later call. */
|
|
39
|
+
export interface Application {
|
|
40
|
+
readonly root: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly displays: readonly DisplayFile[];
|
|
43
|
+
readonly tags: readonly TagRow[];
|
|
44
|
+
readonly tagFiles: readonly string[];
|
|
45
|
+
readonly tagErrors: readonly string[];
|
|
46
|
+
readonly diagnostics: readonly string[];
|
|
47
|
+
readonly files: readonly ScannedFile[];
|
|
48
|
+
}
|
|
49
|
+
/** Parsed tag CSV: rows plus the structural errors found while reading it. */
|
|
50
|
+
export interface TagCsv {
|
|
51
|
+
readonly rows: readonly TagRow[];
|
|
52
|
+
readonly errors: readonly string[];
|
|
53
|
+
}
|
|
54
|
+
/** Split one semicolon-separated CSV line, honouring double quotes. */
|
|
55
|
+
export declare function splitCsv(line: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Parse the HMI tag CSV.
|
|
58
|
+
*
|
|
59
|
+
* @param text - Whole CSV file.
|
|
60
|
+
* @returns Rows plus structural errors; a file with no `###002` marker yields no rows.
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseTagCsv(text: string): TagCsv;
|
|
63
|
+
/**
|
|
64
|
+
* Parse one display XML file.
|
|
65
|
+
*
|
|
66
|
+
* @param file - Relative path inside the export folder.
|
|
67
|
+
* @param text - Whole XML file.
|
|
68
|
+
* @returns The display, or the parse error with a synthetic entry.
|
|
69
|
+
*/
|
|
70
|
+
export declare function parseDisplay(file: string, text: string): DisplayFile;
|
|
71
|
+
/**
|
|
72
|
+
* Scan one export folder.
|
|
73
|
+
*
|
|
74
|
+
* @param fs - Filesystem provider.
|
|
75
|
+
* @param root - Resolved export folder.
|
|
76
|
+
* @param signal - Cancellation.
|
|
77
|
+
* @param maxFiles - Largest number of display/tag files accepted.
|
|
78
|
+
* @returns The scanned application.
|
|
79
|
+
*/
|
|
80
|
+
export declare function scanApplication(fs: FsService, root: string, signal: AbortSignal | undefined, maxFiles: number): Promise<Application>;
|