@uipath/skills 1.204.0 → 1.204.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.cursor-plugin/plugin.json +1 -1
- package/CODEOWNERS +12 -14
- package/package.json +1 -1
- package/skills/uipath-agents/references/coded/embedding-in-flows.md +1 -3
- package/skills/uipath-agents/references/coded/quickstart.md +0 -2
- package/skills/uipath-agents/references/lowcode/capabilities/inline-in-flow/inline-in-flow.md +10 -8
- package/skills/uipath-agents/references/lowcode/prompting/autonomous-agent-prompting-guide.md +1 -1
- package/skills/uipath-human-in-the-loop/SKILL.md +1 -3
- package/skills/uipath-human-in-the-loop/references/hitl-node-apptask.md +0 -2
- package/skills/uipath-human-in-the-loop/references/hitl-node-coded-action-app.md +0 -2
- package/skills/uipath-human-in-the-loop/references/hitl-node-quickform.md +2 -2
- package/skills/uipath-maestro-flow/.maintenance/README.md +265 -0
- package/skills/uipath-maestro-flow/.maintenance/check-all.sh +40 -0
- package/skills/uipath-maestro-flow/.maintenance/check-anchors.sh +101 -0
- package/skills/uipath-maestro-flow/.maintenance/check-depth.sh +132 -0
- package/skills/uipath-maestro-flow/.maintenance/check-link-text.sh +123 -0
- package/skills/uipath-maestro-flow/.maintenance/check-links.sh +73 -0
- package/skills/uipath-maestro-flow/.maintenance/check-orphans.sh +93 -0
- package/skills/uipath-maestro-flow/.maintenance/check-plugin-pairs.sh +39 -0
- package/skills/uipath-maestro-flow/.maintenance/check-template.sh +42 -0
- package/skills/uipath-maestro-flow/.maintenance/check-uip-commands.sh +270 -0
- package/skills/uipath-maestro-flow/.maintenance/check-versions.sh +160 -0
- package/skills/uipath-maestro-flow/SKILL.md +69 -886
- package/skills/uipath-maestro-flow/references/author/CAPABILITY.md +207 -0
- package/skills/uipath-maestro-flow/references/author/brownfield.md +91 -0
- package/skills/uipath-maestro-flow/references/author/editing-operations-cli.md +190 -0
- package/skills/uipath-maestro-flow/references/author/editing-operations-json.md +374 -0
- package/skills/uipath-maestro-flow/references/author/editing-operations.md +104 -0
- package/skills/uipath-maestro-flow/references/author/greenfield.md +420 -0
- package/skills/uipath-maestro-flow/references/author/planning-arch.md +364 -0
- package/skills/uipath-maestro-flow/references/author/planning-impl.md +291 -0
- package/skills/uipath-maestro-flow/references/author/plugins/agent/impl.md +237 -0
- package/skills/uipath-maestro-flow/references/author/plugins/agent/planning.md +97 -0
- package/skills/uipath-maestro-flow/references/author/plugins/agentic-process/impl.md +107 -0
- package/skills/uipath-maestro-flow/references/author/plugins/agentic-process/planning.md +61 -0
- package/skills/uipath-maestro-flow/references/author/plugins/api-workflow/impl.md +108 -0
- package/skills/uipath-maestro-flow/references/author/plugins/api-workflow/planning.md +60 -0
- package/skills/uipath-maestro-flow/references/author/plugins/batch-transform/impl.md +171 -0
- package/skills/uipath-maestro-flow/references/author/plugins/batch-transform/planning.md +72 -0
- package/skills/uipath-maestro-flow/references/author/plugins/connector/impl-inline.md +120 -0
- package/skills/uipath-maestro-flow/references/author/plugins/connector/impl.md +463 -0
- package/skills/uipath-maestro-flow/references/author/plugins/connector/planning.md +186 -0
- package/skills/uipath-maestro-flow/references/author/plugins/connector-trigger/impl.md +517 -0
- package/skills/uipath-maestro-flow/references/author/plugins/connector-trigger/planning.md +115 -0
- package/skills/uipath-maestro-flow/references/author/plugins/conversational-agent/impl.md +309 -0
- package/skills/uipath-maestro-flow/references/author/plugins/conversational-agent/planning.md +133 -0
- package/skills/uipath-maestro-flow/references/author/plugins/data-fabric/impl.md +428 -0
- package/skills/uipath-maestro-flow/references/author/plugins/data-fabric/planning.md +188 -0
- package/skills/uipath-maestro-flow/references/author/plugins/decision/impl.md +83 -0
- package/skills/uipath-maestro-flow/references/author/plugins/decision/planning.md +38 -0
- package/skills/uipath-maestro-flow/references/author/plugins/delay/impl.md +38 -0
- package/skills/uipath-maestro-flow/references/author/plugins/delay/planning.md +53 -0
- package/skills/uipath-maestro-flow/references/author/plugins/end/impl.md +56 -0
- package/skills/uipath-maestro-flow/references/author/plugins/end/planning.md +28 -0
- package/skills/uipath-maestro-flow/references/author/plugins/flow/impl.md +107 -0
- package/skills/uipath-maestro-flow/references/author/plugins/flow/planning.md +58 -0
- package/skills/uipath-maestro-flow/references/author/plugins/hitl/impl.md +181 -0
- package/skills/uipath-maestro-flow/references/author/plugins/hitl/planning.md +166 -0
- package/skills/uipath-maestro-flow/references/author/plugins/http/impl-connector.md +86 -0
- package/skills/uipath-maestro-flow/references/author/plugins/http/impl-manual.md +68 -0
- package/skills/uipath-maestro-flow/references/author/plugins/http/impl.md +173 -0
- package/skills/uipath-maestro-flow/references/author/plugins/http/planning.md +107 -0
- package/skills/uipath-maestro-flow/references/author/plugins/inline-agent/impl.md +540 -0
- package/skills/uipath-maestro-flow/references/author/plugins/inline-agent/planning.md +115 -0
- package/skills/uipath-maestro-flow/references/author/plugins/inline-voice-agent/impl.md +269 -0
- package/skills/uipath-maestro-flow/references/author/plugins/inline-voice-agent/planning.md +128 -0
- package/skills/uipath-maestro-flow/references/author/plugins/ixp/impl.md +424 -0
- package/skills/uipath-maestro-flow/references/author/plugins/ixp/planning.md +95 -0
- package/skills/uipath-maestro-flow/references/author/plugins/loop/impl.md +403 -0
- package/skills/uipath-maestro-flow/references/author/plugins/loop/planning.md +60 -0
- package/skills/uipath-maestro-flow/references/author/plugins/merge/impl.md +43 -0
- package/skills/uipath-maestro-flow/references/author/plugins/merge/planning.md +24 -0
- package/skills/uipath-maestro-flow/references/author/plugins/queue/impl.md +82 -0
- package/skills/uipath-maestro-flow/references/author/plugins/queue/planning.md +44 -0
- package/skills/uipath-maestro-flow/references/author/plugins/rpa/impl.md +117 -0
- package/skills/uipath-maestro-flow/references/author/plugins/rpa/planning.md +61 -0
- package/skills/uipath-maestro-flow/references/author/plugins/scheduled-trigger/impl.md +56 -0
- package/skills/uipath-maestro-flow/references/author/plugins/scheduled-trigger/planning.md +93 -0
- package/skills/uipath-maestro-flow/references/author/plugins/script/impl.md +98 -0
- package/skills/uipath-maestro-flow/references/author/plugins/script/planning.md +42 -0
- package/skills/uipath-maestro-flow/references/author/plugins/subflow/impl.md +164 -0
- package/skills/uipath-maestro-flow/references/author/plugins/subflow/planning.md +35 -0
- package/skills/uipath-maestro-flow/references/author/plugins/summarize/impl.md +189 -0
- package/skills/uipath-maestro-flow/references/author/plugins/summarize/planning.md +66 -0
- package/skills/uipath-maestro-flow/references/author/plugins/switch/impl.md +72 -0
- package/skills/uipath-maestro-flow/references/author/plugins/switch/planning.md +34 -0
- package/skills/uipath-maestro-flow/references/author/plugins/terminate/impl.md +48 -0
- package/skills/uipath-maestro-flow/references/author/plugins/terminate/planning.md +29 -0
- package/skills/uipath-maestro-flow/references/author/plugins/transform/impl.md +252 -0
- package/skills/uipath-maestro-flow/references/author/plugins/transform/planning.md +47 -0
- package/skills/uipath-maestro-flow/references/diagnose/CAPABILITY.md +73 -0
- package/skills/uipath-maestro-flow/references/diagnose/failure-modes.md +353 -0
- package/skills/uipath-maestro-flow/references/diagnose/troubleshooting-guide.md +174 -0
- package/skills/uipath-maestro-flow/references/evaluate/CAPABILITY.md +134 -0
- package/skills/uipath-maestro-flow/references/evaluate/commands-reference.md +376 -0
- package/skills/uipath-maestro-flow/references/evaluate/eval-sets-guide.md +227 -0
- package/skills/uipath-maestro-flow/references/evaluate/evaluators-guide.md +143 -0
- package/skills/uipath-maestro-flow/references/evaluate/running-guide.md +215 -0
- package/skills/uipath-maestro-flow/references/evaluate/upload-safety.md +94 -0
- package/skills/uipath-maestro-flow/references/operate/CAPABILITY.md +77 -0
- package/skills/uipath-maestro-flow/references/operate/manage.md +39 -0
- package/skills/uipath-maestro-flow/references/operate/run.md +121 -0
- package/skills/uipath-maestro-flow/references/operate/ship.md +57 -0
- package/skills/uipath-maestro-flow/references/shared/action-nodes.md +100 -0
- package/skills/uipath-maestro-flow/references/shared/cli-commands.md +269 -0
- package/skills/uipath-maestro-flow/references/shared/cli-conventions.md +178 -0
- package/skills/uipath-maestro-flow/references/shared/file-format.md +582 -0
- package/skills/uipath-maestro-flow/references/shared/node-output-wiring.md +86 -0
- package/skills/uipath-maestro-flow/references/shared/ux-narration-and-todos.md +113 -0
- package/skills/uipath-maestro-flow/references/shared/variables-and-expressions.md +787 -0
- package/skills/uipath-platform/references/integration-service/activities.md +2 -2
- package/skills/uipath-platform/references/integration-service/activity-generation.md +8 -1
- package/skills/uipath-platform/references/integration-service/triggers.md +1 -3
- package/version-manifest.json +1 -1
- package/skills/uipath-maestro-flow/examples/AquariumSafetyStop.flow.ts +0 -26
- package/skills/uipath-maestro-flow/examples/ArchiveCardExtract.flow.ts +0 -38
- package/skills/uipath-maestro-flow/examples/BakeOffEntryForm.flow.ts +0 -27
- package/skills/uipath-maestro-flow/examples/BeeHiveLedger.flow.ts +0 -61
- package/skills/uipath-maestro-flow/examples/BeltProgression.flow.ts +0 -53
- package/skills/uipath-maestro-flow/examples/BirdCountLookup.flow.ts +0 -24
- package/skills/uipath-maestro-flow/examples/ClubDirectory.flow.ts +0 -56
- package/skills/uipath-maestro-flow/examples/ConcertSoundcheck.flow.ts +0 -59
- package/skills/uipath-maestro-flow/examples/DoorbellLog.flow.ts +0 -45
- package/skills/uipath-maestro-flow/examples/FestivalMapScaffold.flow.ts +0 -22
- package/skills/uipath-maestro-flow/examples/FieldTripQuickForm.flow.ts +0 -45
- package/skills/uipath-maestro-flow/examples/FossilCatalogEnrich.flow.ts +0 -26
- package/skills/uipath-maestro-flow/examples/GallerySubmission.flow.ts +0 -67
- package/skills/uipath-maestro-flow/examples/GreenhouseWatering.flow.ts +0 -39
- package/skills/uipath-maestro-flow/examples/HarbourRadioLine.flow.ts +0 -31
- package/skills/uipath-maestro-flow/examples/HerbariumDispatch.flow.ts +0 -34
- package/skills/uipath-maestro-flow/examples/KilnReview.flow.ts +0 -38
- package/skills/uipath-maestro-flow/examples/LibraryDeskChat.flow.ts +0 -39
- package/skills/uipath-maestro-flow/examples/LighthouseSignal.flow.ts +0 -30
- package/skills/uipath-maestro-flow/examples/MeteorShowerPages.flow.ts +0 -39
- package/skills/uipath-maestro-flow/examples/NeighborhoodWalkPlanner.flow.ts +0 -27
- package/skills/uipath-maestro-flow/examples/ObservatorySeeing.flow.ts +0 -51
- package/skills/uipath-maestro-flow/examples/OralHistoryDigest.flow.ts +0 -31
- package/skills/uipath-maestro-flow/examples/PlanetariumConfirmation.flow.ts +0 -34
- package/skills/uipath-maestro-flow/examples/PlantNameAdvisor.flow.ts +0 -28
- package/skills/uipath-maestro-flow/examples/PostcardCaption.flow.ts +0 -44
- package/skills/uipath-maestro-flow/examples/PotteryStudioCallback.flow.ts +0 -41
- package/skills/uipath-maestro-flow/examples/RecipeScaler.flow.ts +0 -62
- package/skills/uipath-maestro-flow/examples/SeedPacketReader.flow.ts +0 -49
- package/skills/uipath-maestro-flow/examples/TideTableConverter.flow.ts +0 -35
- package/skills/uipath-maestro-flow/examples/TrailLogSummary.flow.ts +0 -75
- package/skills/uipath-maestro-flow/examples/WorkshopInventory.flow.ts +0 -27
- package/skills/uipath-maestro-flow/examples/bindings.json +0 -85
- package/skills/uipath-maestro-flow/references/CLI-LOOP.md +0 -309
- package/skills/uipath-maestro-flow/references/agent-resources.md +0 -74
- package/skills/uipath-maestro-flow/references/agent.md +0 -175
- package/skills/uipath-maestro-flow/references/agentic-process.md +0 -41
- package/skills/uipath-maestro-flow/references/api-workflow.md +0 -29
- package/skills/uipath-maestro-flow/references/author.md +0 -178
- package/skills/uipath-maestro-flow/references/batch-transform.md +0 -23
- package/skills/uipath-maestro-flow/references/bindings.md +0 -178
- package/skills/uipath-maestro-flow/references/branch.md +0 -18
- package/skills/uipath-maestro-flow/references/brownfield.md +0 -152
- package/skills/uipath-maestro-flow/references/connector-params.md +0 -624
- package/skills/uipath-maestro-flow/references/conversational.md +0 -77
- package/skills/uipath-maestro-flow/references/data-fabric.md +0 -268
- package/skills/uipath-maestro-flow/references/delay.md +0 -26
- package/skills/uipath-maestro-flow/references/diagnose.md +0 -141
- package/skills/uipath-maestro-flow/references/document-pipeline.md +0 -47
- package/skills/uipath-maestro-flow/references/error-handling.md +0 -75
- package/skills/uipath-maestro-flow/references/evaluate.md +0 -168
- package/skills/uipath-maestro-flow/references/event-trigger.md +0 -155
- package/skills/uipath-maestro-flow/references/form-trigger.md +0 -41
- package/skills/uipath-maestro-flow/references/hitl.md +0 -169
- package/skills/uipath-maestro-flow/references/http.md +0 -105
- package/skills/uipath-maestro-flow/references/inline-agent.md +0 -132
- package/skills/uipath-maestro-flow/references/ixp.md +0 -167
- package/skills/uipath-maestro-flow/references/loops.md +0 -77
- package/skills/uipath-maestro-flow/references/manual-trigger.md +0 -39
- package/skills/uipath-maestro-flow/references/operate.md +0 -204
- package/skills/uipath-maestro-flow/references/or-processes.md +0 -91
- package/skills/uipath-maestro-flow/references/parallel-merge.md +0 -21
- package/skills/uipath-maestro-flow/references/placeholder.md +0 -70
- package/skills/uipath-maestro-flow/references/published-function.md +0 -66
- package/skills/uipath-maestro-flow/references/queue.md +0 -53
- package/skills/uipath-maestro-flow/references/return.md +0 -20
- package/skills/uipath-maestro-flow/references/rpa-workflow.md +0 -27
- package/skills/uipath-maestro-flow/references/scheduled-trigger.md +0 -34
- package/skills/uipath-maestro-flow/references/script.md +0 -52
- package/skills/uipath-maestro-flow/references/subflow.md +0 -33
- package/skills/uipath-maestro-flow/references/summarize.md +0 -20
- package/skills/uipath-maestro-flow/references/switch.md +0 -20
- package/skills/uipath-maestro-flow/references/terminate.md +0 -22
- package/skills/uipath-maestro-flow/references/transform.md +0 -32
- package/skills/uipath-maestro-flow/references/voice.md +0 -70
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Verify every `uip` command referenced in this skill's markdown actually exists.
|
|
3
|
+
# Usage: bash .maintenance/check-uip-commands.sh [--strict] [file1.md ...]
|
|
4
|
+
# Output: BAD lines per unknown command, then "commands_checked=N unknown=M" summary.
|
|
5
|
+
#
|
|
6
|
+
# Scans fenced code blocks (```bash, ```sh, ```shell, ```zsh, ```console, or
|
|
7
|
+
# unlabelled ```) under this skill for lines that begin with `uip `, extracts
|
|
8
|
+
# the command path (tokens before the first flag, placeholder, or shell
|
|
9
|
+
# metachar), and verifies it against `uip <path> --help`. Help output only —
|
|
10
|
+
# no command is ever executed for real.
|
|
11
|
+
#
|
|
12
|
+
# How verification works: `uip <bogus> --help` silently falls back to the
|
|
13
|
+
# parent's help, so exit code is not a reliable signal. Instead, we walk the
|
|
14
|
+
# path level by level and confirm each next segment appears in the parent's
|
|
15
|
+
# `Subcommands[].Name` list. Help responses are cached per prefix.
|
|
16
|
+
#
|
|
17
|
+
# Skips:
|
|
18
|
+
# - Inline backtick references like `uip ...` (only fenced blocks are scanned)
|
|
19
|
+
# - Files matching --skip-glob
|
|
20
|
+
#
|
|
21
|
+
# --strict: exit 2 if `uip` is not on PATH (CI mode). Default: warn and exit 0.
|
|
22
|
+
#
|
|
23
|
+
# Exits non-zero if any unknown command is referenced.
|
|
24
|
+
|
|
25
|
+
set -e
|
|
26
|
+
|
|
27
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
28
|
+
cd "$ROOT" || exit 1
|
|
29
|
+
|
|
30
|
+
STRICT=0
|
|
31
|
+
FILES=()
|
|
32
|
+
for arg in "$@"; do
|
|
33
|
+
case "$arg" in
|
|
34
|
+
--strict) STRICT=1 ;;
|
|
35
|
+
*) FILES+=("$arg") ;;
|
|
36
|
+
esac
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
if ! command -v uip >/dev/null 2>&1; then
|
|
40
|
+
if [ "$STRICT" -eq 1 ]; then
|
|
41
|
+
echo "uip not found on PATH (--strict)" >&2
|
|
42
|
+
exit 2
|
|
43
|
+
fi
|
|
44
|
+
echo "uip not found on PATH; skipping (use --strict to fail)" >&2
|
|
45
|
+
echo ""
|
|
46
|
+
echo "commands_checked=0 unknown=0"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
51
|
+
echo "python3 not found on PATH" >&2
|
|
52
|
+
exit 2
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [ "${#FILES[@]}" -eq 0 ]; then
|
|
56
|
+
# Scan the skill's published surface only: SKILL.md + references/.
|
|
57
|
+
# Skips .maintenance/, scratch files at the skill root (PLAN.md, PR_BODY.md),
|
|
58
|
+
# and anything else that isn't part of what agents load.
|
|
59
|
+
while IFS= read -r f; do
|
|
60
|
+
FILES+=("$f")
|
|
61
|
+
done < <({ [ -f SKILL.md ] && echo "./SKILL.md"; /usr/bin/find ./references -type f -name '*.md' 2>/dev/null; } | /usr/bin/sort)
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
if [ "${#FILES[@]}" -eq 0 ]; then
|
|
65
|
+
echo ""
|
|
66
|
+
echo "commands_checked=0 unknown=0"
|
|
67
|
+
exit 0
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
export UIP_BIN="$(command -v uip)"
|
|
71
|
+
export SKILL_ROOT="$ROOT"
|
|
72
|
+
|
|
73
|
+
python3 - "${FILES[@]}" <<'PYEOF'
|
|
74
|
+
import json
|
|
75
|
+
import os
|
|
76
|
+
import re
|
|
77
|
+
import subprocess
|
|
78
|
+
import sys
|
|
79
|
+
from pathlib import Path
|
|
80
|
+
|
|
81
|
+
UIP = os.environ["UIP_BIN"]
|
|
82
|
+
SKILL_ROOT = Path(os.environ["SKILL_ROOT"])
|
|
83
|
+
files = [Path(p) for p in sys.argv[1:]]
|
|
84
|
+
|
|
85
|
+
# Cache value: (subcommands_set, takes_positional_args) or None for invalid prefix
|
|
86
|
+
_help_cache: dict[tuple, tuple[set, bool] | None] = {}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def get_help(prefix):
|
|
90
|
+
if prefix in _help_cache:
|
|
91
|
+
return _help_cache[prefix]
|
|
92
|
+
# `--output json` is required: top-level `uip --help` defaults to plain
|
|
93
|
+
# text; other levels default to JSON but accept the flag too. Forcing it
|
|
94
|
+
# makes parsing deterministic.
|
|
95
|
+
cmd = [UIP, *prefix, "--help", "--output", "json"]
|
|
96
|
+
try:
|
|
97
|
+
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
98
|
+
except Exception:
|
|
99
|
+
_help_cache[prefix] = None
|
|
100
|
+
return None
|
|
101
|
+
# uip prints non-JSON noise around the help payload — sometimes a banner
|
|
102
|
+
# before (e.g. `Tool factory already registered ...`), sometimes a human
|
|
103
|
+
# usage block after. Use raw_decode to grab the first complete JSON object.
|
|
104
|
+
out = proc.stdout
|
|
105
|
+
brace = out.find("{")
|
|
106
|
+
if brace < 0:
|
|
107
|
+
_help_cache[prefix] = None
|
|
108
|
+
return None
|
|
109
|
+
try:
|
|
110
|
+
data, _ = json.JSONDecoder().raw_decode(out[brace:])
|
|
111
|
+
except json.JSONDecodeError:
|
|
112
|
+
_help_cache[prefix] = None
|
|
113
|
+
return None
|
|
114
|
+
inner = data.get("Data", {})
|
|
115
|
+
resolved = inner.get("Command", "")
|
|
116
|
+
expected = prefix[-1] if prefix else "uip"
|
|
117
|
+
if resolved != expected:
|
|
118
|
+
_help_cache[prefix] = None
|
|
119
|
+
return None
|
|
120
|
+
subs = set()
|
|
121
|
+
for entry in inner.get("Subcommands", []) or []:
|
|
122
|
+
name = entry.get("Name", "")
|
|
123
|
+
leaf = name.split(None, 1)[0]
|
|
124
|
+
if leaf:
|
|
125
|
+
# Subcommand names may be pipe-aliased (e.g. `or|orchestrator`).
|
|
126
|
+
# Register each alias separately so either form is accepted.
|
|
127
|
+
for alias in leaf.split("|"):
|
|
128
|
+
if alias:
|
|
129
|
+
subs.add(alias)
|
|
130
|
+
takes_args = bool(inner.get("Arguments"))
|
|
131
|
+
_help_cache[prefix] = (subs, takes_args)
|
|
132
|
+
return _help_cache[prefix]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def verify_path(path):
|
|
136
|
+
prefix = ()
|
|
137
|
+
for seg in path:
|
|
138
|
+
info = get_help(prefix)
|
|
139
|
+
if info is None:
|
|
140
|
+
return False, prefix[-1] if prefix else seg, []
|
|
141
|
+
subs, takes_args = info
|
|
142
|
+
if seg not in subs:
|
|
143
|
+
# If the parent is a leaf (no subcommands) and accepts positional
|
|
144
|
+
# args, this token is an arg — path is valid up to here.
|
|
145
|
+
if not subs and takes_args:
|
|
146
|
+
return True, "", []
|
|
147
|
+
import difflib
|
|
148
|
+
return False, seg, difflib.get_close_matches(seg, sorted(subs), n=3, cutoff=0.5)
|
|
149
|
+
prefix = prefix + (seg,)
|
|
150
|
+
return True, "", []
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
FENCE_RE = re.compile(r"^```([a-zA-Z0-9_+-]*)\s*$")
|
|
154
|
+
ACCEPTED_LANGS = {"", "bash", "sh", "shell", "zsh", "console"}
|
|
155
|
+
# Inline single-backtick spans. Greedy is fine: ` cannot appear inside a
|
|
156
|
+
# single-backtick span by definition (use double-backtick spans for that, which
|
|
157
|
+
# we deliberately don't scan — they're rare and usually contain code samples).
|
|
158
|
+
INLINE_RE = re.compile(r"`([^`\n]+)`")
|
|
159
|
+
# Per-line opt-out marker: `<!-- uip-check-skip -->` anywhere on the line
|
|
160
|
+
# suppresses checking for that line. Used for intentional historical references
|
|
161
|
+
# (e.g. CLI version-comparison tables that document a removed prefix). For
|
|
162
|
+
# table rows, place the marker inside a cell (e.g. `| ... | ... <!-- uip-check-skip --> |`)
|
|
163
|
+
# so it doesn't break table structure — HTML comments render as nothing.
|
|
164
|
+
SKIP_MARKER = "<!-- uip-check-skip -->"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
SUBCOMMAND_RE = re.compile(r"^[a-z][a-z0-9-]*$")
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def is_terminator(tok):
|
|
171
|
+
# A real uip subcommand is a lowercase kebab-case identifier. Anything else
|
|
172
|
+
# (flags, placeholders, paths, comments, quoted strings, shell metachars,
|
|
173
|
+
# positional args) ends the path.
|
|
174
|
+
if not tok:
|
|
175
|
+
return True
|
|
176
|
+
if tok.startswith("#"):
|
|
177
|
+
return True
|
|
178
|
+
if tok in {"|", ">", ">>", "<", "&&", "||", ";", "&", "$(", "`"}:
|
|
179
|
+
return True
|
|
180
|
+
return not SUBCOMMAND_RE.match(tok)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def extract_path_from_uip_line(content):
|
|
184
|
+
"""Tokenize a uip line and walk to extract the command path.
|
|
185
|
+
|
|
186
|
+
Returns the path list (possibly empty for bare `uip`).
|
|
187
|
+
Returns None if the line doesn't start with `uip`.
|
|
188
|
+
"""
|
|
189
|
+
if content.startswith("$ "):
|
|
190
|
+
content = content[2:]
|
|
191
|
+
if not (content.startswith("uip ") or content.rstrip() == "uip"):
|
|
192
|
+
return None
|
|
193
|
+
tokens = content.split()
|
|
194
|
+
path = []
|
|
195
|
+
for tok in tokens[1:]:
|
|
196
|
+
if is_terminator(tok):
|
|
197
|
+
break
|
|
198
|
+
path.append(tok)
|
|
199
|
+
return path
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def extract_uip_commands(md_path):
|
|
203
|
+
try:
|
|
204
|
+
text = md_path.read_text(encoding="utf-8")
|
|
205
|
+
except Exception:
|
|
206
|
+
return
|
|
207
|
+
lines = text.splitlines()
|
|
208
|
+
in_fence = False
|
|
209
|
+
fence_lang = ""
|
|
210
|
+
i = 0
|
|
211
|
+
while i < len(lines):
|
|
212
|
+
line = lines[i]
|
|
213
|
+
m = FENCE_RE.match(line.strip())
|
|
214
|
+
if m:
|
|
215
|
+
if not in_fence:
|
|
216
|
+
in_fence = True
|
|
217
|
+
fence_lang = m.group(1).lower()
|
|
218
|
+
else:
|
|
219
|
+
in_fence = False
|
|
220
|
+
fence_lang = ""
|
|
221
|
+
i += 1
|
|
222
|
+
continue
|
|
223
|
+
if SKIP_MARKER in line:
|
|
224
|
+
i += 1
|
|
225
|
+
continue
|
|
226
|
+
if in_fence:
|
|
227
|
+
if fence_lang in ACCEPTED_LANGS:
|
|
228
|
+
start = i
|
|
229
|
+
joined = line
|
|
230
|
+
while joined.rstrip().endswith("\\") and i + 1 < len(lines):
|
|
231
|
+
joined = joined.rstrip()[:-1] + " " + lines[i + 1]
|
|
232
|
+
i += 1
|
|
233
|
+
path = extract_path_from_uip_line(joined.lstrip())
|
|
234
|
+
if path:
|
|
235
|
+
yield (start + 1, path)
|
|
236
|
+
else:
|
|
237
|
+
# Inline backtick spans outside fenced blocks.
|
|
238
|
+
for match in INLINE_RE.finditer(line):
|
|
239
|
+
path = extract_path_from_uip_line(match.group(1).strip())
|
|
240
|
+
if path:
|
|
241
|
+
yield (i + 1, path)
|
|
242
|
+
i += 1
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
references = {}
|
|
246
|
+
for md in files:
|
|
247
|
+
for line_no, path in extract_uip_commands(md):
|
|
248
|
+
references.setdefault(tuple(path), []).append((md, line_no))
|
|
249
|
+
|
|
250
|
+
unknown = 0
|
|
251
|
+
for path_tuple, locs in sorted(references.items()):
|
|
252
|
+
ok, bad, suggestions = verify_path(list(path_tuple))
|
|
253
|
+
if ok:
|
|
254
|
+
continue
|
|
255
|
+
idx = list(path_tuple).index(bad) if bad in path_tuple else 0
|
|
256
|
+
parent = "uip" + ("" if idx == 0 else " " + " ".join(path_tuple[:idx]))
|
|
257
|
+
cmd_str = "uip " + " ".join(path_tuple)
|
|
258
|
+
sug = f" (did you mean: {', '.join(suggestions)}?)" if suggestions else ""
|
|
259
|
+
for f, ln in locs:
|
|
260
|
+
try:
|
|
261
|
+
rel = f.relative_to(SKILL_ROOT).as_posix()
|
|
262
|
+
except ValueError:
|
|
263
|
+
rel = str(f)
|
|
264
|
+
print(f'BAD {rel}:{ln} {cmd_str} — "{bad}" not a subcommand of "{parent}"{sug}')
|
|
265
|
+
unknown += 1
|
|
266
|
+
|
|
267
|
+
print()
|
|
268
|
+
print(f"commands_checked={len(references)} unknown={unknown}")
|
|
269
|
+
sys.exit(1 if unknown else 0)
|
|
270
|
+
PYEOF
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Verify this skill never pins a .flow version as authoritative in prose, and
|
|
3
|
+
# never hardcodes the top-level .flow `version` literal.
|
|
4
|
+
# Usage: bash .maintenance/check-versions.sh [file1.md ...]
|
|
5
|
+
# Output: BAD lines per violation, then "lines_checked=N violations=M" summary.
|
|
6
|
+
#
|
|
7
|
+
# Rationale: the .flow top-level `version` and node `typeVersion` are owned by
|
|
8
|
+
# `uip maestro flow init` / `uip maestro flow registry get`. Hardcoding them in
|
|
9
|
+
# docs rots silently when the CLI/registry advances (e.g. core.action.http.v2
|
|
10
|
+
# 2.0 -> 2.1, core.trigger.scheduled 1.0 -> 1.1, top-level 1.1 -> 1.2). The rule
|
|
11
|
+
# is: reference the live command, never pin the number as "current"/"required".
|
|
12
|
+
#
|
|
13
|
+
# Two violation classes (both high-confidence — chosen to NOT re-flag the many
|
|
14
|
+
# legitimate illustrative `"typeVersion": "1.0"` JSON examples that are governed
|
|
15
|
+
# by an adjacent registry-sourcing note):
|
|
16
|
+
#
|
|
17
|
+
# 1. PROSE-PIN — prose that states a version as current or mandatory, e.g.
|
|
18
|
+
# `currently "1.1"`, `the registry currently emits "1.0"`, `must be "2.0"`,
|
|
19
|
+
# `use version "1.0"`. These claims go stale.
|
|
20
|
+
# 2. TOPLEVEL — a hardcoded top-level `.flow` `"version": "x.y"` literal.
|
|
21
|
+
# Top-level version must always be the `uip maestro flow init` placeholder
|
|
22
|
+
# (e.g. `"<version from \`uip maestro flow init\`>"`), never a number.
|
|
23
|
+
#
|
|
24
|
+
# Explicitly NOT flagged:
|
|
25
|
+
# - `"typeVersion": "x.y"` literals in node JSON examples (legitimate when
|
|
26
|
+
# paired with a sourcing note; too many true-illustrative cases to flag).
|
|
27
|
+
# - `bindings_v2.json` `"version": "2.0"` — a fixed schema constant, not a
|
|
28
|
+
# .flow version. Distinguished by the surrounding `"resources"` key.
|
|
29
|
+
#
|
|
30
|
+
# Skipping: add `<!-- version-check-skip -->` anywhere on a line to suppress it
|
|
31
|
+
# (e.g. a historical/version-comparison note that documents an old literal on
|
|
32
|
+
# purpose). For table rows, place the marker inside a cell.
|
|
33
|
+
#
|
|
34
|
+
# Scans SKILL.md + references/**/*.md. Skips .maintenance/ and root scratch
|
|
35
|
+
# files (PLAN.md, PR_BODY.md). Exits non-zero if any violation is found.
|
|
36
|
+
|
|
37
|
+
set -e
|
|
38
|
+
|
|
39
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
40
|
+
cd "$ROOT" || exit 1
|
|
41
|
+
|
|
42
|
+
if ! command -v python3 >/dev/null 2>&1; then
|
|
43
|
+
echo "python3 not found on PATH" >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
FILES=("$@")
|
|
48
|
+
if [ "${#FILES[@]}" -eq 0 ]; then
|
|
49
|
+
while IFS= read -r f; do
|
|
50
|
+
FILES+=("$f")
|
|
51
|
+
done < <({ [ -f SKILL.md ] && echo "./SKILL.md"; /usr/bin/find ./references -type f -name '*.md' 2>/dev/null; } | /usr/bin/sort)
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ "${#FILES[@]}" -eq 0 ]; then
|
|
55
|
+
echo ""
|
|
56
|
+
echo "lines_checked=0 violations=0"
|
|
57
|
+
exit 0
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
python3 - "${FILES[@]}" <<'PY'
|
|
61
|
+
import re, sys
|
|
62
|
+
|
|
63
|
+
files = sys.argv[1:]
|
|
64
|
+
|
|
65
|
+
SKIP_MARKER = "<!-- version-check-skip -->"
|
|
66
|
+
|
|
67
|
+
# A quoted version literal: "1.0", "1.1", "2.0", "1.0.0", etc.
|
|
68
|
+
VER = r'"\d+\.\d+(?:\.\d+)?"'
|
|
69
|
+
|
|
70
|
+
# Class 1 — PROSE-PIN: a version literal stated as current / mandatory.
|
|
71
|
+
# Two sub-patterns (note: docs wrap versions in backticks, e.g. `"1.1"`, so the
|
|
72
|
+
# gap class must NOT exclude backticks):
|
|
73
|
+
# (a) a pinning verb followed within a short window by a version literal —
|
|
74
|
+
# `currently "1.1"`, `the registry currently emits "1.0"`, `must be "2.0"`.
|
|
75
|
+
# (b) an inline assignment of a version field to a literal in prose —
|
|
76
|
+
# `typeVersion: "2.0"`, `version: "1.1"` (the original http/impl.md:27 bug
|
|
77
|
+
# had no pin-verb — it just stated `typeVersion: "2.0"`).
|
|
78
|
+
PROSE_PIN_VERB = re.compile(
|
|
79
|
+
r'(currently|current\b|must be|use version|emits|emit|is currently|as of)'
|
|
80
|
+
r'[^\n]{0,40}?' + VER,
|
|
81
|
+
re.IGNORECASE,
|
|
82
|
+
)
|
|
83
|
+
PROSE_PIN_ASSIGN = re.compile(
|
|
84
|
+
r'(typeVersion|version)\s*[:=]\s*' + VER,
|
|
85
|
+
re.IGNORECASE,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
def prose_pin(line):
|
|
89
|
+
return PROSE_PIN_VERB.search(line) or PROSE_PIN_ASSIGN.search(line)
|
|
90
|
+
|
|
91
|
+
# Class 2 — TOPLEVEL: a hardcoded top-level `.flow` `"version": "x.y"`.
|
|
92
|
+
# Only the .flow document's OWN top-level version is in scope — NOT
|
|
93
|
+
# `definitions[].version` (node manifest versions), NOT eval-file `version`,
|
|
94
|
+
# NOT `bindings_v2.json` `version`, NOT `connectorDetail.configuration.version`.
|
|
95
|
+
# We identify a true top-level .flow version by its sibling keys: a real .flow
|
|
96
|
+
# object has `"nodes"` and `"edges"` (and usually `"name"`) within a few lines.
|
|
97
|
+
# Definitions entries instead carry `"nodeType"`; bindings_v2 carries
|
|
98
|
+
# `"resources"`; eval files carry `"evaluatorRefs"` / `"evaluatorTypeId"` /
|
|
99
|
+
# `"evaluations"`. Presence of any of those disqualifies the match.
|
|
100
|
+
TOPLEVEL = re.compile(r'"version"\s*:\s*' + VER)
|
|
101
|
+
|
|
102
|
+
_FLOW_SIBLINGS = ('"nodes"', '"edges"')
|
|
103
|
+
_DISQUALIFY = ('"nodeType"', '"resources"', '"evaluatorRefs"',
|
|
104
|
+
'"evaluatorTypeId"', '"evaluations"', '"connectorDetail"')
|
|
105
|
+
|
|
106
|
+
def is_flow_toplevel_version(lines, idx):
|
|
107
|
+
# Look at a window around the `"version"` line for the discriminating keys,
|
|
108
|
+
# bounded to the current fenced block so it never bleeds into an adjacent
|
|
109
|
+
# JSON example (e.g. a following `definitions` entry with `"nodeType"`).
|
|
110
|
+
lo = idx - 1
|
|
111
|
+
while lo >= 0 and not lines[lo].strip().startswith("```"):
|
|
112
|
+
lo -= 1
|
|
113
|
+
lo += 1
|
|
114
|
+
hi = idx + 1
|
|
115
|
+
while hi < len(lines) and not lines[hi].strip().startswith("```"):
|
|
116
|
+
hi += 1
|
|
117
|
+
window = "\n".join(lines[lo:hi])
|
|
118
|
+
if any(k in window for k in _DISQUALIFY):
|
|
119
|
+
return False
|
|
120
|
+
return all(k in window for k in _FLOW_SIBLINGS)
|
|
121
|
+
|
|
122
|
+
lines_checked = 0
|
|
123
|
+
violations = 0
|
|
124
|
+
|
|
125
|
+
for path in files:
|
|
126
|
+
try:
|
|
127
|
+
with open(path, encoding="utf-8") as fh:
|
|
128
|
+
lines = fh.read().splitlines()
|
|
129
|
+
except OSError:
|
|
130
|
+
continue
|
|
131
|
+
|
|
132
|
+
in_fence = False
|
|
133
|
+
for i, line in enumerate(lines):
|
|
134
|
+
stripped = line.strip()
|
|
135
|
+
# Track fenced code blocks so PROSE-PIN only fires on real prose.
|
|
136
|
+
if stripped.startswith("```"):
|
|
137
|
+
in_fence = not in_fence
|
|
138
|
+
continue
|
|
139
|
+
lines_checked += 1
|
|
140
|
+
if SKIP_MARKER in line:
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
# Class 1: prose only (outside fences).
|
|
144
|
+
if not in_fence and prose_pin(line):
|
|
145
|
+
print(f"BAD {path}:{i+1} PROSE-PIN — version stated as current/required; reference `registry get`/`flow init` instead")
|
|
146
|
+
print(f" {stripped[:140]}")
|
|
147
|
+
violations += 1
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
# Class 2: top-level `.flow` "version" literal — JSON examples only,
|
|
151
|
+
# and only when the surrounding object is a genuine .flow document.
|
|
152
|
+
if in_fence and TOPLEVEL.search(line) and is_flow_toplevel_version(lines, i):
|
|
153
|
+
print(f"BAD {path}:{i+1} TOPLEVEL — hardcoded top-level `.flow` `version` literal; use the `uip maestro flow init` placeholder")
|
|
154
|
+
print(f" {stripped[:140]}")
|
|
155
|
+
violations += 1
|
|
156
|
+
|
|
157
|
+
print()
|
|
158
|
+
print(f"lines_checked={lines_checked} violations={violations}")
|
|
159
|
+
sys.exit(1 if violations else 0)
|
|
160
|
+
PY
|