systemlink-cli 1.13.4__tar.gz → 1.13.6__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 (93) hide show
  1. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/PKG-INFO +1 -1
  2. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/pyproject.toml +1 -1
  3. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/_version.py +1 -1
  4. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/comment_click.py +1 -1
  5. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/completion_click.py +1 -1
  6. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/config_click.py +1 -1
  7. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/dataframe_click.py +1 -1
  8. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/dff_click.py +1 -1
  9. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/example_click.py +1 -1
  10. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/feed_click.py +1 -1
  11. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/file_click.py +1 -1
  12. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/main.py +52 -3
  13. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/mcp_click.py +1 -1
  14. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/notebook_click.py +1 -1
  15. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/policy_click.py +1 -1
  16. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/routine_click.py +1 -1
  17. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skill_click.py +1 -1
  18. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/SKILL.md +30 -20
  19. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-notebook/SKILL.md +114 -10
  20. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-notebook/references/interfaces.md +91 -1
  21. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-notebook/references/notebook-patterns.md +53 -12
  22. systemlink_cli-1.13.6/slcli/skills/systemlink-webapp/SKILL.md +188 -0
  23. systemlink_cli-1.13.6/slcli/skills/systemlink-webapp/references/angular-ui-packages.md +154 -0
  24. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-webapp/references/deployment.md +7 -5
  25. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-webapp/references/nimble-angular.md +2 -0
  26. systemlink_cli-1.13.6/slcli/skills/systemlink-webapp/references/troubleshooting.md +100 -0
  27. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/spec_click.py +1 -1
  28. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/templates_click.py +1 -1
  29. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/testmonitor_click.py +1 -1
  30. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/webapp_click.py +1 -1
  31. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/workitem_click.py +1 -1
  32. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/workspace_click.py +1 -1
  33. systemlink_cli-1.13.4/slcli/skills/systemlink-webapp/SKILL.md +0 -855
  34. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/LICENSE +0 -0
  35. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/dff-editor/editor.js +0 -0
  36. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/dff-editor/index.html +0 -0
  37. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/__init__.py +0 -0
  38. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/__main__.py +0 -0
  39. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/asset_click.py +0 -0
  40. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/cli_formatters.py +0 -0
  41. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/cli_utils.py +0 -0
  42. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/config.py +0 -0
  43. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/dff_decorators.py +0 -0
  44. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/example_loader.py +0 -0
  45. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/example_provisioner.py +0 -0
  46. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/README.md +0 -0
  47. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/_schema/schema-v1.0.json +0 -0
  48. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/demo-complete-workflow/README.md +0 -0
  49. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/demo-complete-workflow/config.yaml +0 -0
  50. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/demo-test-plans/README.md +0 -0
  51. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/demo-test-plans/config.yaml +0 -0
  52. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/exercise-5-1-parametric-insights/README.md +0 -0
  53. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/exercise-5-1-parametric-insights/config.yaml +0 -0
  54. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/exercise-7-1-test-plans/README.md +0 -0
  55. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/exercise-7-1-test-plans/config.yaml +0 -0
  56. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/README.md +0 -0
  57. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/config.yaml +0 -0
  58. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +0 -0
  59. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +0 -0
  60. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +0 -0
  61. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
  62. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/function_click.py +0 -0
  63. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/function_templates.py +0 -0
  64. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/mcp_reachability.py +0 -0
  65. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/mcp_server.py +0 -0
  66. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/platform.py +0 -0
  67. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/policy_utils.py +0 -0
  68. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/profiles.py +0 -0
  69. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/response_handlers.py +0 -0
  70. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/rich_output.py +0 -0
  71. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/nipkg-file-package/SKILL.md +0 -0
  72. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/references/analysis-recipes.md +0 -0
  73. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/references/commands.md +0 -0
  74. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/references/datasheet-workflow.md +0 -0
  75. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/references/filtering.md +0 -0
  76. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/slcli/references/troubleshooting.md +0 -0
  77. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-job-debugging/SKILL.md +0 -0
  78. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-python-test/SKILL.md +0 -0
  79. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-webapp/references/layout-patterns.md +0 -0
  80. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/skills/systemlink-webapp/references/systemlink-services.md +0 -0
  81. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/ssl_trust.py +0 -0
  82. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/state_click.py +0 -0
  83. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/system_click.py +0 -0
  84. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/system_query_utils.py +0 -0
  85. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/table_utils.py +0 -0
  86. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/tag_click.py +0 -0
  87. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/universal_handlers.py +0 -0
  88. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/user_click.py +0 -0
  89. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/utils.py +0 -0
  90. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/web_editor.py +0 -0
  91. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/workflow_preview.py +0 -0
  92. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/workflows_click.py +0 -0
  93. {systemlink_cli-1.13.4 → systemlink_cli-1.13.6}/slcli/workspace_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: systemlink-cli
3
- Version: 1.13.4
3
+ Version: 1.13.6
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.13.4"
3
+ version = "1.13.6"
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.13.4"
4
+ __version__ = "1.13.6"
@@ -188,7 +188,7 @@ def register_comment_commands(cli: Any) -> None:
188
188
  @cli.group()
189
189
  @click.pass_context
190
190
  def comment(ctx: click.Context) -> None:
191
- """Manage comments on SystemLink resources.
191
+ """Manage SystemLink comments.
192
192
 
193
193
  Comments can be attached to any resource identified by a resource type
194
194
  and resource ID. Known resource types: testmonitor:Result, niapm:Asset,
@@ -386,7 +386,7 @@ def register_completion_command(cli: Any) -> None:
386
386
  help="Install completion script to shell config file",
387
387
  )
388
388
  def completion(shell: Optional[str], install: bool) -> None:
389
- """Generate and optionally install shell completion scripts.
389
+ """Generate shell completion scripts and optionally install them.
390
390
 
391
391
  Examples:
392
392
  # Generate bash completion script
@@ -225,7 +225,7 @@ def register_config_commands(cli: Any) -> None:
225
225
 
226
226
  @cli.group()
227
227
  def config() -> None:
228
- """Manage slcli configuration and profiles.
228
+ """Manage slcli settings and profiles.
229
229
 
230
230
  Profiles allow you to configure multiple SystemLink environments
231
231
  (dev, test, prod) and switch between them easily.
@@ -646,7 +646,7 @@ def register_dataframe_commands(cli: Any) -> None:
646
646
  @cli.group()
647
647
  @click.pass_context
648
648
  def dataframe(ctx: click.Context) -> None:
649
- """Manage SystemLink DataFrame tables and row data."""
649
+ """Manage SystemLink DataFrame tables and rows."""
650
650
  if ctx.invoked_subcommand is not None:
651
651
  require_feature("dataframe_service")
652
652
 
@@ -312,7 +312,7 @@ def register_dff_commands(cli: Any) -> None:
312
312
  @cli.group(name="customfield")
313
313
  @click.pass_context
314
314
  def dff(ctx: click.Context) -> None:
315
- """Manage custom field (DFF) configurations."""
315
+ """Manage SystemLink custom field configurations."""
316
316
  # Check for platform feature availability
317
317
  # Only check if a subcommand is being invoked (not just --help)
318
318
  if ctx.invoked_subcommand is not None:
@@ -121,7 +121,7 @@ def register_example_commands(cli: Any) -> None:
121
121
 
122
122
  @cli.group()
123
123
  def example() -> None:
124
- """Manage example resource configurations.
124
+ """Browse and provision example SystemLink resource configurations.
125
125
 
126
126
  Examples help you quickly set up demo systems for training,
127
127
  testing, or evaluation. Each example includes systems, assets,
@@ -436,7 +436,7 @@ def register_feed_commands(cli: Any) -> None:
436
436
 
437
437
  @cli.group()
438
438
  def feed() -> None:
439
- """Manage NI Package Manager feeds and their packages.
439
+ """Manage SystemLink package feeds and packages.
440
440
 
441
441
  Feeds are package repositories used by NI Package Manager to install
442
442
  software on test systems. Supports Windows (.nipkg) and NI Linux RT
@@ -508,7 +508,7 @@ def register_file_commands(cli: Any) -> None:
508
508
 
509
509
  @cli.group()
510
510
  def file() -> None:
511
- """Manage files in SystemLink File Service."""
511
+ """Manage SystemLink files."""
512
512
  pass
513
513
 
514
514
  @file.command(name="list")
@@ -49,6 +49,55 @@ else:
49
49
  click = rich_click_module
50
50
 
51
51
 
52
+ def _configure_rich_click_command_groups() -> None:
53
+ """Configure top-level help command groups when rich-click is available."""
54
+ rich_click_config = getattr(click, "rich_click", None)
55
+ if rich_click_config is None:
56
+ return
57
+
58
+ # Keep the command-name/help split consistent across top-level panels so
59
+ # descriptions start at the same column in every group.
60
+ rich_click_config.STYLE_COMMANDS_TABLE_EXPAND = True
61
+ rich_click_config.STYLE_COMMANDS_TABLE_COLUMN_WIDTH_RATIO = (1, 5)
62
+
63
+ rich_click_config.COMMAND_GROUPS = {
64
+ "slcli": [
65
+ {
66
+ "name": "Configure",
67
+ "commands": ["config", "login", "logout", "info", "completion", "example"],
68
+ },
69
+ {
70
+ "name": "Administer",
71
+ "commands": ["auth", "user", "workspace"],
72
+ },
73
+ {
74
+ "name": "Operate",
75
+ "commands": [
76
+ "asset",
77
+ "system",
78
+ "state",
79
+ "tag",
80
+ "file",
81
+ "feed",
82
+ "comment",
83
+ "dataframe",
84
+ ],
85
+ },
86
+ {
87
+ "name": "Build & Automate",
88
+ "commands": ["notebook", "routine", "webapp", "customfield", "skill", "mcp"],
89
+ },
90
+ {
91
+ "name": "Validate & Plan",
92
+ "commands": ["testmonitor", "template", "spec", "workitem"],
93
+ },
94
+ ]
95
+ }
96
+
97
+
98
+ _configure_rich_click_command_groups()
99
+
100
+
52
101
  def get_version() -> str:
53
102
  """Get version from _version.py (built binary) or pyproject.toml (development)."""
54
103
  try:
@@ -193,7 +242,7 @@ def login(
193
242
  set_current: bool,
194
243
  readonly: bool,
195
244
  ) -> None:
196
- """Save SystemLink credentials to a profile.
245
+ """Create or update a SystemLink profile with credentials.
197
246
 
198
247
  This is an alias for 'slcli config add'. Use that command
199
248
  for the same functionality and more configuration options.
@@ -225,7 +274,7 @@ def login(
225
274
  @click.option("--all", "remove_all", is_flag=True, help="Remove all profiles")
226
275
  @click.option("--force", "-f", is_flag=True, help="Skip confirmation prompt")
227
276
  def logout(profile: Optional[str], remove_all: bool, force: bool) -> None:
228
- """Remove stored SystemLink credentials.
277
+ """Remove stored SystemLink profiles and credentials.
229
278
 
230
279
  By default, removes the current profile. Use --profile to remove a specific
231
280
  profile, or --all to remove all profiles.
@@ -309,7 +358,7 @@ def logout(profile: Optional[str], remove_all: bool, force: bool) -> None:
309
358
  @click.option("--format", "-f", type=click.Choice(["table", "json"]), default="table")
310
359
  @click.option("--skip-health", is_flag=True, default=False, help="Skip live service health checks.")
311
360
  def info(format: str, skip_health: bool) -> None:
312
- """Show current configuration and detected platform."""
361
+ """Show the active profile, configuration, and platform status."""
313
362
  from .profiles import ProfileConfig, get_active_profile
314
363
 
315
364
  platform_info = get_platform_info(skip_health=skip_health)
@@ -143,7 +143,7 @@ def register_mcp_commands(cli: Any) -> None:
143
143
 
144
144
  @cli.group()
145
145
  def mcp() -> None:
146
- """MCP (Model Context Protocol) server integration for AI assistants."""
146
+ """Run and configure the SystemLink MCP server for AI assistants."""
147
147
 
148
148
  @mcp.command(name="serve")
149
149
  @click.option(
@@ -629,7 +629,7 @@ def register_notebook_commands(cli: Any) -> None:
629
629
 
630
630
  @cli.group()
631
631
  def notebook() -> None: # pragma: no cover - Click wiring
632
- """Manage notebooks (init locally, manage remotely, run)."""
632
+ """Create, run, and manage SystemLink notebooks."""
633
633
  pass
634
634
 
635
635
  # ------------------------------------------------------------------
@@ -32,7 +32,7 @@ def register_policy_commands(cli: Any) -> None:
32
32
 
33
33
  @cli.group(name="auth")
34
34
  def auth() -> None:
35
- """Manage SystemLink auth policies and policy templates."""
35
+ """Manage SystemLink authorization policies and policy templates."""
36
36
  pass
37
37
 
38
38
  @auth.group(name="policy")
@@ -127,7 +127,7 @@ def register_routine_commands(cli: Any) -> None:
127
127
 
128
128
  @cli.group()
129
129
  def routine() -> None:
130
- """Manage SystemLink routines (v1: notebook scheduling, v2: event-action)."""
130
+ """Manage SystemLink routines."""
131
131
  pass
132
132
 
133
133
  # ------------------------------------------------------------------
@@ -200,7 +200,7 @@ def register_skill_commands(cli: Any) -> None:
200
200
 
201
201
  @cli.group()
202
202
  def skill() -> None:
203
- """Manage AI agent skills for most agents and Claude."""
203
+ """Install and manage AI assistant skills."""
204
204
 
205
205
  @skill.command(name="install")
206
206
  @click.option(
@@ -24,6 +24,16 @@ compatibility: >-
24
24
  metadata:
25
25
  author: ni-kismet
26
26
  version: "2.0"
27
+ ---
28
+
29
+ ## Command style
30
+
31
+ Prefer long option names in generated commands and examples. Use `--format json`,
32
+ `--take 25`, `--workspace Default`, and `--output path.json` instead of `-f json`,
33
+ `-t 25`, `-w Default`, or `-o path.json`.
34
+
35
+ Only mention short aliases when explicitly documenting that they exist.
36
+
27
37
  # --system SYSTEM_ID Assign a system (by minion/system ID). Repeatable.
28
38
  # --fixture ASSET_ID Assign a fixture/slot (by asset ID, asset type FIXTURE). Repeatable.
29
39
  # --dut ASSET_ID Assign a DUT (by asset ID, asset type DEVICE_UNDER_TEST). Repeatable.
@@ -36,22 +46,22 @@ slcli workitem schedule <WORK_ITEM_ID> \
36
46
  [--system SYSTEM_ID]... [--fixture ASSET_ID]... [--dut ASSET_ID]...
37
47
 
38
48
  # Work item template subgroup
39
- slcli workitem template list [-w WORKSPACE] [--filter TEXT] [-t INT] [-f json]
40
- slcli workitem template get <TEMPLATE_ID> [-f json]
41
- slcli workitem template create --name TEXT --type TEXT --template-group TEXT [-w WORKSPACE] [OPTIONS]
49
+ slcli workitem template list [--workspace WORKSPACE] [--filter TEXT] [--take INT] [--format json]
50
+ slcli workitem template get <TEMPLATE_ID> [--format json]
51
+ slcli workitem template create --name TEXT --type TEXT --template-group TEXT [--workspace WORKSPACE] [OPTIONS]
42
52
  slcli workitem template update <TEMPLATE_ID> [--name TEXT] [--description TEXT] [--summary TEXT]
43
53
  slcli workitem template delete <TEMPLATE_ID>... [--yes]
44
54
 
45
55
  # Workflow subgroup
46
- slcli workitem workflow list [-w WORKSPACE] [-t INT] [-f json]
47
- slcli workitem workflow get [--id WORKFLOW_ID] [--name NAME] [-f json]
56
+ slcli workitem workflow list [--workspace WORKSPACE] [--take INT] [--format json]
57
+ slcli workitem workflow get [--id WORKFLOW_ID] [--name NAME] [--format json]
48
58
  slcli workitem workflow init [--name TEXT] [--directory DIR] # Scaffold a local workflow file
49
- slcli workitem workflow create --file PATH [-w WORKSPACE] # Create from JSON file
50
- slcli workitem workflow import --file PATH [-w WORKSPACE] # Import workflow from JSON
51
- slcli workitem workflow export [--id WORKFLOW_ID] [--name NAME] [-o FILE] # Export to JSON
59
+ slcli workitem workflow create --file PATH [--workspace WORKSPACE] # Create from JSON file
60
+ slcli workitem workflow import --file PATH [--workspace WORKSPACE] # Import workflow from JSON
61
+ slcli workitem workflow export [--id WORKFLOW_ID] [--name NAME] [--output FILE] # Export to JSON
52
62
  slcli workitem workflow update --id WORKFLOW_ID --file PATH # Update from JSON file
53
63
  slcli workitem workflow delete --id WORKFLOW_ID [--yes]
54
- slcli workitem workflow preview [--file PATH] [--id WORKFLOW_ID] [--html] [--no-open] [-o FILE]
64
+ slcli workitem workflow preview [--file PATH] [--id WORKFLOW_ID] [--html] [--no-open] [--output FILE]
55
65
  ```
56
66
 
57
67
  **Create work item options:**
@@ -82,9 +92,9 @@ Scaffold, package, and publish custom web applications to SystemLink.
82
92
  ```bash
83
93
  slcli webapp init <DIRECTORY> # Scaffold the Angular starter
84
94
  slcli webapp manifest init <DIRECTORY> [OPTIONS] # Create nipkg.config.json for packaging
85
- slcli webapp pack [FOLDER] [--config FILE] [-o OUTPUT_FILE] # Package a webapp into a .nipkg
86
- slcli webapp list [-w WORKSPACE] [-t INT] [-f json]
87
- slcli webapp get <WEBAPP_ID> [-f json]
95
+ slcli webapp pack [FOLDER] [--config FILE] [--output OUTPUT_FILE] # Package a webapp into a .nipkg
96
+ slcli webapp list [--workspace WORKSPACE] [--take INT] [--format json]
97
+ slcli webapp get <WEBAPP_ID> [--format json]
88
98
  slcli webapp publish PATH [--workspace NAME] # Upload and publish a webapp
89
99
  slcli webapp delete <WEBAPP_ID>
90
100
  slcli webapp open <WEBAPP_ID> # Open webapp URL in browser
@@ -95,19 +105,19 @@ slcli webapp open <WEBAPP_ID> # Open webapp URL in br
95
105
  Create, inspect, import, export, and revert saved software states managed by the SystemLink Systems State service.
96
106
 
97
107
  ```bash
98
- slcli state list [-w WORKSPACE] [--architecture CHOICE] [--distribution CHOICE] [-t INT] [-f json]
99
- slcli state get <STATE_ID> [-f json]
108
+ slcli state list [--workspace WORKSPACE] [--architecture CHOICE] [--distribution CHOICE] [--take INT] [--format json]
109
+ slcli state get <STATE_ID> [--format json]
100
110
  slcli state create --name TEXT --distribution CHOICE --architecture CHOICE [OPTIONS]
101
111
  slcli state update <STATE_ID> [OPTIONS]
102
112
  slcli state delete <STATE_ID> [--yes]
103
113
 
104
114
  slcli state import --name TEXT --distribution CHOICE --architecture CHOICE --file PATH [OPTIONS]
105
- slcli state replace-content <STATE_ID> --file PATH [--change-description TEXT] [-f json]
115
+ slcli state replace-content <STATE_ID> --file PATH [--change-description TEXT] [--format json]
106
116
  slcli state export <STATE_ID> [--version VERSION] [--inline | --output FILE]
107
117
  slcli state capture <SYSTEM_ID> [--inline | --output FILE]
108
118
 
109
- slcli state history <STATE_ID> [-t INT] [-f json]
110
- slcli state version <STATE_ID> <VERSION> [-f json]
119
+ slcli state history <STATE_ID> [--take INT] [--format json]
120
+ slcli state version <STATE_ID> <VERSION> [--format json]
111
121
  slcli state revert <STATE_ID> <VERSION> [--yes]
112
122
  ```
113
123
 
@@ -148,7 +158,7 @@ Install pre-built demo configurations (systems, assets, DUTs, templates, etc.)
148
158
  for training, testing, or evaluation.
149
159
 
150
160
  ```bash
151
- slcli example list [-f json] # List available examples
161
+ slcli example list [--format json] # List available examples
152
162
  slcli example info <EXAMPLE_ID> # Show example details
153
163
  slcli example install <EXAMPLE_ID> [--workspace NAME] # Provision example resources
154
164
  slcli example delete <EXAMPLE_ID> [--workspace NAME] # Remove provisioned resources
@@ -175,7 +185,7 @@ SystemLink Enterprise (SLE) or require a specific microservice to be deployed.
175
185
 
176
186
  ```bash
177
187
  slcli info # Shows platform type and service health
178
- slcli info -f json # Machine-readable; check .services for per-service status
188
+ slcli info --format json # Machine-readable; check .services for per-service status
179
189
  ```
180
190
 
181
191
  | Command group | Required service | SLE | SLS | Notes |
@@ -231,7 +241,7 @@ to disable caching for debugging.
231
241
 
232
242
  ## Key rules
233
243
 
234
- 1. **Always use `-f json`** when piping output to `jq` or doing programmatic analysis.
244
+ 1. **Always use `--format json`** when piping output to `jq` or doing programmatic analysis.
235
245
  2. **Use `--summary --group-by`** for aggregation instead of fetching all records and counting.
236
246
  3. **Use convenience filters first** (e.g., `--status FAILED`), fall back to `--filter` for complex queries.
237
247
  4. **Parameterize `--filter` queries** — use `--substitution` instead of string interpolation.
@@ -20,6 +20,84 @@ argument-hint: 'Describe the notebook purpose and what data it should report on'
20
20
  - Creating a test data analysis notebook
21
21
  - Deploying a notebook to SystemLink via `slcli`
22
22
 
23
+ ## Important: Python Client Quirks
24
+
25
+ The `nisystemlink-clients` Python package has a few ergonomics quirks to be aware of:
26
+
27
+ ### API naming inconsistency
28
+
29
+ Client methods use Python `snake_case`, but request model fields use `camelCase`. This requires careful attention:
30
+
31
+ ```python
32
+ # ❌ WRONG: Using Python snake_case (very intuitive but incorrect)
33
+ CreateResultRequest(program_name="My Test", file_ids=[file_id])
34
+
35
+ # ✅ CORRECT: Must use camelCase field names from the request model
36
+ CreateResultRequest(programName="My Test", fileIds=[file_id])
37
+
38
+ # Methods stay snake_case:
39
+ client.create_results(request) # This is correct
40
+ client.create_steps(...) # This is correct
41
+ ```
42
+
43
+ Always check the request model constructor signature, not what "feels" Pythonic.
44
+
45
+ ### Partial-success responses
46
+
47
+ Operations like `create_results()` and `create_steps()` return partial-success wrapper types
48
+ (e.g., `CreateStepsPartialSuccess`) even when successful. These contain both success and failure data:
49
+
50
+ ```python
51
+ from nisystemlink.clients.testmonitor import TestMonitorClient
52
+ from nisystemlink.clients.testmonitor.models import CreateStepRequest
53
+
54
+ client = TestMonitorClient()
55
+ response = client.create_steps([CreateStepRequest(...)])
56
+
57
+ # Success and failures are both in the response
58
+ if response.failed:
59
+ print(f"Failed to create {len(response.failed)} steps")
60
+ if response.created:
61
+ print(f"Successfully created {len(response.created)} steps")
62
+ ```
63
+
64
+ ### Limited service coverage
65
+
66
+ The Python client does **not cover all SystemLink services**. The most important gaps for notebooks (see the [client repo](https://github.com/ni/nisystemlink-clients-python) for the current full list):
67
+
68
+ - ❌ **Notebook Execution** — no Python client for execution lifecycle management
69
+ - ❌ **Routines v1/v2** — no Python client for scheduling/triggering
70
+ - ❌ **Systems State** — no Python client for system health queries
71
+ - ❌ **Comments** — no Python client for resource annotations
72
+ - ❌ **User Data** — no Python client for key-value stores
73
+ - ❌ **Tag Historian** — no Python client for time-series history
74
+
75
+ For these services, use REST calls directly via the `requests` library or SystemLink's OpenAPI SDKs.
76
+
77
+ ### Public import paths
78
+
79
+ This skill uses two distinct Python SDK namespaces — be careful not to mix them:
80
+
81
+ - **`nisystemlink.clients.*`** — the typed Python client (`nisystemlink-clients` package). Use public top-level imports.
82
+ - **`systemlink.clients.nisysmgmt.*`** — a separate OpenAPI-generated SDK used only for Systems queries.
83
+
84
+ For `nisystemlink.clients`, always import from the public top-level modules, not private `_module` paths:
85
+
86
+ ```python
87
+ # ✅ CORRECT: Public paths (nisystemlink-clients)
88
+ from nisystemlink.clients.file import FileClient
89
+ from nisystemlink.clients.testmonitor import TestMonitorClient
90
+ from nisystemlink.clients.testmonitor.models import CreateResultRequest, CreateStepRequest
91
+
92
+ # ❌ WRONG: Private module paths (may change or be removed)
93
+ from nisystemlink.clients.testmonitor._test_monitor_client import TestMonitorClient
94
+ from nisystemlink.clients.testmonitor.models._create_result_request import CreateResultRequest
95
+
96
+ # Separate SDK — used only for Systems queries:
97
+ from systemlink.clients.nisysmgmt.api.systems_api import SystemsApi
98
+ from systemlink.clients.nisysmgmt.models.query_systems_request import QuerySystemsRequest
99
+ ```
100
+
23
101
  ## Notebook Structure
24
102
 
25
103
  Every SystemLink notebook follows this cell pattern:
@@ -199,33 +277,59 @@ import scrapbook as sb
199
277
  from systemlink.clients.nisysmgmt.api.systems_api import SystemsApi
200
278
  from systemlink.clients.nisysmgmt.models.query_systems_request import QuerySystemsRequest
201
279
 
202
- # Test results
280
+ # Test results (remember: camelCase field names in request models)
203
281
  from nisystemlink.clients.testmonitor import TestMonitorClient
282
+ from nisystemlink.clients.testmonitor.models import CreateResultRequest, CreateStepRequest
204
283
  from nisystemlink.clients.core import HttpConfigurationManager
205
284
 
206
285
  # Assets
207
286
  from nisystemlink.clients.assetmanagement import AssetManagementClient
208
287
 
209
- # Direct HTTP (when no typed client exists)
288
+ # Direct HTTP (when no typed client exists or for missing services)
210
289
  import requests
211
290
  config = HttpConfigurationManager.get_configuration()
212
291
  base_url = config.server_uri.rstrip("/")
213
- headers = {"x-ni-api-key": config.api_keys[0]}
292
+ api_keys = getattr(config, "api_keys", {})
293
+ api_key = api_keys.get("x-ni-api-key") if isinstance(api_keys, dict) else None
294
+ if not api_key:
295
+ raise RuntimeError("Configure an x-ni-api-key before using REST fallbacks.")
296
+ headers = {"x-ni-api-key": api_key}
214
297
  ```
215
298
 
299
+ ### Available Python client services
300
+
301
+ The Python client covers these **15 main services**:
302
+ - `alarm`, `artifact`, `assetmanagement`, `dataframe`, `feeds`, `file`, `notebook`,
303
+ `notification`, `product`, `spec`, `systems`, `tag`, `test_plan`, `testmonitor`, `work_item`
304
+
305
+ ### Missing services (use REST directly)
306
+
307
+ If you need these services, call the REST API directly using `requests` and the OpenAPI docs:
308
+ - **Notebook Execution** — execution lifecycle (use OpenAPI directly)
309
+ - **Routines v1/v2** — scheduling/triggering (use OpenAPI directly)
310
+ - **Systems State** — system health/connection status (use OpenAPI directly)
311
+ - **Comments** — resource annotations (use OpenAPI directly)
312
+ - **User Data** — key-value stores (use OpenAPI directly)
313
+ - **Tag Historian** — time-series history (use OpenAPI directly)
314
+ - **Auth**, **User**, and others — see full list in service-gaps documentation
315
+
216
316
  ## Client and API References
217
317
 
218
- - Prefer the official Python client libraries when they cover the target service:
318
+ - **Python client repository** full source and examples:
219
319
  https://github.com/ni/nisystemlink-clients-python
220
- - If a SystemLink service does not have a Python client yet, call the REST API
221
- directly and use the hosted OpenAPI docs to discover endpoints and schemas:
320
+ - **SystemLink OpenAPI docs** for all services, including those without Python clients:
222
321
  https://demo-api.lifecyclesolutions.ni.com/niapis/
223
- - For notebook patterns and end-to-end examples, check the SystemLink Enterprise
224
- examples repository:
322
+ - **SystemLink Enterprise examples** end-to-end patterns:
225
323
  https://github.com/ni/systemlink-enterprise-examples/
226
324
 
227
- When using direct HTTP, prefer the OpenAPI docs first to confirm the service base
228
- path, request body shape, and response schema before writing notebook code.
325
+ When using the Python client:
326
+ - Always check the request model constructor signature for camelCase field names (they won't match Python snake_case)
327
+ - Expect `create_*` operations to return partial-success wrapper types; inspect `.created` and `.failed` attributes
328
+ - Use public import paths from top-level modules, not private `_module` paths
329
+
330
+ When a service lacks a Python client, use OpenAPI docs to discover the endpoint path,
331
+ request body shape, and response schema before writing HTTP calls.
332
+
229
333
  ## Systems Query Pattern
230
334
 
231
335
  The `SystemsApi` uses a projection/filter pattern for querying:
@@ -14,6 +14,20 @@ Prefer `create --interface ...` when you are creating a new notebook. Use
14
14
  `update --interface ...` for in-place interface changes on an existing notebook.
15
15
  Delete and re-create only if the server rejects the update.
16
16
 
17
+ ## Service Availability Note
18
+
19
+ The Python client does not cover every SystemLink service. Key gaps that affect
20
+ automation interfaces (see the `nisystemlink-clients` repository for the current
21
+ service list):
22
+
23
+ - ❌ **Notebook Execution** — No Python client for checking execution status or logs
24
+ - ❌ **Routines v1/v2** — No Python client for scheduling; use REST directly or `slcli routine` in scheduled shells
25
+ - ❌ **Comments** — No Python client for adding resource annotations
26
+ - ❌ **User** — No Python client for querying users/workspaces (use REST directly)
27
+
28
+ For these services in notebooks, call the REST API directly via the `requests`
29
+ library and the service-specific SystemLink OpenAPI docs.
30
+
17
31
  ## Available Interfaces
18
32
 
19
33
  | Interface | Use Case |
@@ -56,7 +70,12 @@ Parameters typically include:
56
70
  ### Periodic Execution
57
71
 
58
72
  No special parameter requirements. Typically uses fixed configuration
59
- or reads from tags/files. Can be scheduled via routines:
73
+ or reads from tags/files. Can be scheduled via routines (no Python client available).
74
+
75
+ **Note:** The Python client does not have a Routines service. Use `slcli routine` to
76
+ schedule notebooks, or call the Routines REST API directly.
77
+
78
+ Create a scheduled routine via CLI:
60
79
 
61
80
  ```bash
62
81
  slcli routine create --api-version v1 \
@@ -66,6 +85,31 @@ slcli routine create --api-version v1 \
66
85
  --schedule '{"startTime":"2026-01-01T00:00:00Z","repeat":"DAY"}'
67
86
  ```
68
87
 
88
+ Or create a scheduled routine via REST using `HttpConfigurationManager` and `requests`:
89
+
90
+ ```python
91
+ import requests
92
+ from nisystemlink.clients.core import HttpConfigurationManager
93
+
94
+ config = HttpConfigurationManager.get_configuration()
95
+ base_url = config.server_uri.rstrip("/")
96
+ api_keys = getattr(config, "api_keys", {})
97
+ api_key = api_keys.get("x-ni-api-key") if isinstance(api_keys, dict) else None
98
+ if not api_key:
99
+ raise RuntimeError("Configure an x-ni-api-key before using REST fallbacks.")
100
+ headers = {"x-ni-api-key": api_key}
101
+
102
+ payload = {
103
+ "name": "Daily Report",
104
+ "type": "SCHEDULED",
105
+ "notebookId": "<NOTEBOOK_ID>",
106
+ "schedule": {"startTime": "<START_TIME_ISO8601>", "repeat": "DAY"}
107
+ }
108
+
109
+ resp = requests.post(f"{base_url}/niroutine/v1/routines", json=payload, headers=headers)
110
+ resp.raise_for_status()
111
+ ```
112
+
69
113
  ### Work Item Automations
70
114
 
71
115
  Use this interface for notebooks that act on selected work items (close, update,
@@ -80,3 +124,49 @@ Parameters are injected by the work item system:
80
124
  **Critical:** `work_item_ids` must be typed as `"string[]"` (not `"string"`),
81
125
  default to `[]` in both papermill and the code cell, and `systemlink.version`
82
126
  must be `1`. See the systemlink-notebook skill for the full metadata example.
127
+
128
+ **Service note:** The Python client has `work_item` service for querying and updating
129
+ work items, but does not have a `comments` service. If your automation needs to add
130
+ comments or notes, call the Comments REST API directly via `requests` library.
131
+
132
+ ## Using REST When Python Clients Are Missing
133
+
134
+ If a notebook needs a service without a Python client, use `requests` and the OpenAPI docs:
135
+
136
+ ```python
137
+ import requests
138
+ from nisystemlink.clients.core import HttpConfigurationManager
139
+
140
+ config = HttpConfigurationManager.get_configuration()
141
+ base_url = config.server_uri.rstrip("/")
142
+ api_keys = getattr(config, "api_keys", {})
143
+ api_key = api_keys.get("x-ni-api-key") if isinstance(api_keys, dict) else None
144
+ if not api_key:
145
+ raise RuntimeError("Configure an x-ni-api-key before using REST fallbacks.")
146
+ headers = {"x-ni-api-key": api_key}
147
+
148
+ # Example: Add a comment to a work item (Comments service not available in Python)
149
+ comment_payload = {
150
+ "resourceId": work_item_id,
151
+ "resourceType": "WorkItem",
152
+ "content": "Automated note from notebook"
153
+ }
154
+
155
+ resp = requests.post(
156
+ f"{base_url}/nicomments/v1/comments",
157
+ json=comment_payload,
158
+ headers=headers
159
+ )
160
+ resp.raise_for_status()
161
+ comment = resp.json()
162
+ ```
163
+
164
+ Common missing services you might need:
165
+
166
+ - **Comments** — `/nicomments/v1/comments`
167
+ - **Routines v1/v2** — `/niroutine/v1/routines` or `/niroutine/v2/routines`
168
+ - **User** — `/niuser/v1/users` or `/niuser/v1/users/query`
169
+ - **Systems State** — `/nisystemsstate/v1/states`
170
+ - **Tag Historian** — check the service-specific OpenAPI docs instead of assuming `/niapis/...`
171
+
172
+ Always check the OpenAPI docs to confirm the correct endpoint path and request schema before implementing REST calls.