systemlink-cli 1.11.0__tar.gz → 1.11.1__tar.gz

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.
Files changed (88) hide show
  1. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/PKG-INFO +1 -1
  2. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/pyproject.toml +1 -1
  3. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/_version.py +1 -1
  4. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-notebook/SKILL.md +76 -3
  5. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-notebook/references/notebook-patterns.md +27 -2
  6. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/LICENSE +0 -0
  7. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/dff-editor/editor.js +0 -0
  8. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/dff-editor/index.html +0 -0
  9. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/__init__.py +0 -0
  10. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/__main__.py +0 -0
  11. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/asset_click.py +0 -0
  12. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/cli_formatters.py +0 -0
  13. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/cli_utils.py +0 -0
  14. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/comment_click.py +0 -0
  15. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/completion_click.py +0 -0
  16. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/config.py +0 -0
  17. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/config_click.py +0 -0
  18. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/dff_click.py +0 -0
  19. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/dff_decorators.py +0 -0
  20. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/example_click.py +0 -0
  21. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/example_loader.py +0 -0
  22. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/example_provisioner.py +0 -0
  23. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/README.md +0 -0
  24. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/_schema/schema-v1.0.json +0 -0
  25. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/demo-complete-workflow/README.md +0 -0
  26. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/demo-complete-workflow/config.yaml +0 -0
  27. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/demo-test-plans/README.md +0 -0
  28. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/demo-test-plans/config.yaml +0 -0
  29. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/exercise-5-1-parametric-insights/README.md +0 -0
  30. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/exercise-5-1-parametric-insights/config.yaml +0 -0
  31. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/exercise-7-1-test-plans/README.md +0 -0
  32. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/exercise-7-1-test-plans/config.yaml +0 -0
  33. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/README.md +0 -0
  34. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/config.yaml +0 -0
  35. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +0 -0
  36. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +0 -0
  37. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +0 -0
  38. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
  39. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/feed_click.py +0 -0
  40. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/file_click.py +0 -0
  41. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/function_click.py +0 -0
  42. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/function_templates.py +0 -0
  43. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/main.py +0 -0
  44. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/mcp_click.py +0 -0
  45. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/mcp_reachability.py +0 -0
  46. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/mcp_server.py +0 -0
  47. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/notebook_click.py +0 -0
  48. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/platform.py +0 -0
  49. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/policy_click.py +0 -0
  50. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/policy_utils.py +0 -0
  51. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/profiles.py +0 -0
  52. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/response_handlers.py +0 -0
  53. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/rich_output.py +0 -0
  54. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/routine_click.py +0 -0
  55. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skill_click.py +0 -0
  56. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/nipkg-file-package/SKILL.md +0 -0
  57. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/SKILL.md +0 -0
  58. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/references/analysis-recipes.md +0 -0
  59. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/references/commands.md +0 -0
  60. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/references/datasheet-workflow.md +0 -0
  61. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/references/filtering.md +0 -0
  62. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/slcli/references/troubleshooting.md +0 -0
  63. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-job-debugging/SKILL.md +0 -0
  64. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-notebook/references/interfaces.md +0 -0
  65. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-python-test/SKILL.md +0 -0
  66. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-webapp/SKILL.md +0 -0
  67. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-webapp/references/deployment.md +0 -0
  68. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-webapp/references/layout-patterns.md +0 -0
  69. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-webapp/references/nimble-angular.md +0 -0
  70. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/skills/systemlink-webapp/references/systemlink-services.md +0 -0
  71. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/spec_click.py +0 -0
  72. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/ssl_trust.py +0 -0
  73. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/system_click.py +0 -0
  74. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/system_query_utils.py +0 -0
  75. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/table_utils.py +0 -0
  76. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/tag_click.py +0 -0
  77. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/templates_click.py +0 -0
  78. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/testmonitor_click.py +0 -0
  79. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/universal_handlers.py +0 -0
  80. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/user_click.py +0 -0
  81. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/utils.py +0 -0
  82. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/web_editor.py +0 -0
  83. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/webapp_click.py +0 -0
  84. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/workflow_preview.py +0 -0
  85. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/workflows_click.py +0 -0
  86. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/workitem_click.py +0 -0
  87. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/workspace_click.py +0 -0
  88. {systemlink_cli-1.11.0 → systemlink_cli-1.11.1}/slcli/workspace_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: systemlink-cli
3
- Version: 1.11.0
3
+ Version: 1.11.1
4
4
  Summary: SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates.
5
5
  License-File: LICENSE
6
6
  Author: Fred Visser
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "systemlink-cli"
3
- version = "1.11.0"
3
+ version = "1.11.1"
4
4
  description = "SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates."
5
5
  authors = ["Fred Visser <fred.visser@emerson.com>"]
6
6
  packages = [{ include = "slcli" }]
@@ -1,4 +1,4 @@
1
1
  """Version information for slcli."""
2
2
 
3
3
  # This file is auto-generated. Do not edit manually.
4
- __version__ = "1.11.0"
4
+ __version__ = "1.11.1"
@@ -71,7 +71,8 @@ in the cell's `.metadata` field for SystemLink to recognize the parameters and o
71
71
 
72
72
  - `papermill.parameters` keys **must** match the variable names in the code cell
73
73
  - `systemlink.parameters[].id` **must** match the variable names in the code cell
74
- - `systemlink.outputs[].id` **must** match the key used in the result dict passed to `sb.glue`
74
+ - `systemlink.outputs[].id` **must** match the `id` field in each output object in the
75
+ `result` list passed to `sb.glue('result', result)`
75
76
  - `tags: ["parameters"]` is **required** — this is how papermill identifies the cell
76
77
  - `systemlink.version` must be `2` for most notebooks, or `1` for **Work Item Automations**
77
78
  - Supported parameter types: `string`, `integer`, `float`, `boolean`, `string[]`
@@ -140,6 +141,21 @@ result = [{
140
141
  sb.glue('result', result)
141
142
  ```
142
143
 
144
+ ### Output validation guardrails
145
+
146
+ - Ensure `result` is a list of output objects, not a dict.
147
+ - Ensure each output object has: `display_name`, `id`, `type`, and `data`.
148
+ - Ensure `type` is one of the supported output types and matches metadata.
149
+ - Ensure output `id` exactly matches `systemlink.outputs[].id`.
150
+ - For `data_frame`, ensure `data.columns` and `data.values` are present and aligned.
151
+
152
+ For Systems Grid notebooks, validate that:
153
+
154
+ - The first column is exactly `minion id`.
155
+ - The first value in each row is the system ID string.
156
+ - For single-column grid reports, use exactly two columns: `minion id` and the report value column.
157
+ - If the notebook is intended to populate one grid column, avoid extra columns unless explicitly required.
158
+
143
159
  ### Systems Grid reports
144
160
 
145
161
  When the notebook is used as a Systems Grid column, the `data_frame` output
@@ -152,6 +168,26 @@ df_dict = {
152
168
  }
153
169
  ```
154
170
 
171
+ Common Systems Grid pattern for one metric per system:
172
+
173
+ ```python
174
+ metric_by_system = {item['id']: item['metric_value'] for item in data.data}
175
+ df = pd.DataFrame.from_dict(metric_by_system, orient='index', columns=['metric'])
176
+
177
+ df_dict = {
178
+ 'columns': ['minion id', 'metric'],
179
+ 'values': df.reset_index().values.tolist()
180
+ }
181
+
182
+ result = [{
183
+ 'display_name': 'Metric',
184
+ 'id': 'metric_output',
185
+ 'type': 'data_frame',
186
+ 'data': df_dict
187
+ }]
188
+ sb.glue('result', result)
189
+ ```
190
+
155
191
  ## Common Imports
156
192
 
157
193
  ```python
@@ -172,7 +208,6 @@ from nisystemlink.clients.assetmanagement import AssetManagementClient
172
208
 
173
209
  # Direct HTTP (when no typed client exists)
174
210
  import requests
175
- from nisystemlink.clients.core import HttpConfigurationManager
176
211
  config = HttpConfigurationManager.get_configuration()
177
212
  base_url = config.server_uri.rstrip("/")
178
213
  headers = {"x-ni-api-key": config.api_keys[0]}
@@ -191,7 +226,6 @@ headers = {"x-ni-api-key": config.api_keys[0]}
191
226
 
192
227
  When using direct HTTP, prefer the OpenAPI docs first to confirm the service base
193
228
  path, request body shape, and response schema before writing notebook code.
194
-
195
229
  ## Systems Query Pattern
196
230
 
197
231
  The `SystemsApi` uses a projection/filter pattern for querying:
@@ -210,6 +244,22 @@ query_result = api.get_systems_by_query(query=query)
210
244
  data = await query_result
211
245
  ```
212
246
 
247
+ ### Async and response handling guardrails
248
+
249
+ - In notebook cells, prefer top-level `await` over `asyncio.run(...)`.
250
+ - Do not call `asyncio.run(...)` inside notebook execution cells; kernels may already have an active event loop.
251
+ - `get_systems_by_query` can return typed response objects (for example `QuerySystemsResponse`). Prefer `data.data` (or `getattr(data, 'data', ...)`) over assuming a plain dict/list.
252
+
253
+ Safe extraction pattern:
254
+
255
+ ```python
256
+ query_result = api.get_systems_by_query(query=query)
257
+ data = await query_result
258
+ systems = getattr(data, 'data', None)
259
+ if systems is None:
260
+ systems = data.get('data', data) if isinstance(data, dict) else data
261
+ ```
262
+
213
263
  ### Common filter expressions
214
264
 
215
265
  | Filter | Description |
@@ -318,6 +368,29 @@ the server rejects the update.
318
368
  reading the `Workspace` field from the active profile. Do not assume "Default" or
319
369
  prompt the user unless `slcli info` shows no workspace configured.
320
370
 
371
+ ## Execution Validation Checklist
372
+
373
+ After create/update, always validate with a fresh (non-cached) execution before concluding success:
374
+
375
+ ```bash
376
+ slcli notebook execute sync -n <NOTEBOOK_ID> -w "<WORKSPACE_NAME>" --no-cache -f json
377
+ ```
378
+
379
+ Validation steps:
380
+
381
+ 1. Confirm `status` is `SUCCEEDED` and `errorCode` is `NO_ERROR`.
382
+ 2. Confirm output `id` and `type` match parameters-cell metadata.
383
+ 3. Confirm `data.columns` and `data.values` shape matches the target interface.
384
+ 4. If output still looks old, check `cachedResult`; rerun with `--no-cache`.
385
+
386
+ ## Known Failure Modes and Fixes
387
+
388
+ - `ValueError: No kernel name found in notebook`: restore notebook-level `metadata.kernelspec`.
389
+ - Notebook output not shown in SystemLink UI: restore parameters-cell `systemlink` metadata and `tags: ["parameters"]`.
390
+ - Systems Grid format mismatch: ensure first column is `minion id` and output is a valid `data_frame` payload.
391
+ - Runtime loop errors (`asyncio.run() cannot be called from a running event loop`): replace `asyncio.run(...)` with top-level `await`.
392
+ - Result appears unchanged after update: rerun with `--no-cache` and re-check returned execution JSON.
393
+
321
394
  ## Example
322
395
 
323
396
  See [notebook-patterns.md](./references/notebook-patterns.md) for a complete
@@ -22,6 +22,7 @@ Import Python modules for executing the notebook.
22
22
 
23
23
  **Cell 2 — Imports (code)**
24
24
  ```python
25
+ import re
25
26
  import pandas as pd
26
27
  import scrapbook as sb
27
28
 
@@ -99,8 +100,32 @@ The cell metadata must include:
99
100
  ```python
100
101
  api = SystemsApi()
101
102
 
102
- projection = f'new(id, packages.data["{package}"].displayversion, packages.data["{package}"].version)'
103
- filter = (systems_filter or "!string.IsNullOrEmpty(id)") + f' && packages.data.keys.Contains("{package}")'
103
+ def _escape_filter_value(value: str) -> str:
104
+ """Escape backslashes first, then quotes, for safe quoted filter literals."""
105
+ return value.replace("\\", "\\\\").replace('"', '\\"')
106
+
107
+ def _validate_package_name(value: str) -> str:
108
+ normalized = value.strip()
109
+ if not re.fullmatch(r"[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?", normalized):
110
+ raise ValueError("package must only contain letters, numbers, dot, dash, or underscore")
111
+ return normalized
112
+
113
+ def _validate_filter_fragment(value: str) -> str:
114
+ normalized = value.strip()
115
+ if not normalized:
116
+ return "!string.IsNullOrEmpty(id)"
117
+ if not re.fullmatch(r'[A-Za-z0-9_ ."\-()\[\],:&|=!<>]*', normalized):
118
+ raise ValueError("systems_filter contains unsupported characters")
119
+ return normalized
120
+
121
+ safe_package = _escape_filter_value(_validate_package_name(package))
122
+ base_filter = _validate_filter_fragment(systems_filter)
123
+
124
+ projection = (
125
+ f'new(id, packages.data["{safe_package}"].displayversion, '
126
+ f'packages.data["{safe_package}"].version)'
127
+ )
128
+ filter = base_filter + f' && packages.data.keys.Contains("{safe_package}")'
104
129
 
105
130
  query_sys_request = QuerySystemsRequest(skip=0, projection=projection, filter=filter)
106
131
  query_result = api.get_systems_by_query(query=query_sys_request)
File without changes