mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 08:01:35 +00:00
fix(system_prompts): resolve nested local command groups in CLI docs generator
The CLI docs generator anchored on the first `new Command()` in a file and
never resolved locally-defined command groups passed as
`.command("name", localCmd)`. For datatable this flattened the nested
`migrate` group: it emitted `datatable new/up/down` plus a bare
`datatable migrate`, and mislabeled the datatable command with the migrate
group's description. jobs was broken the same way (its description was pull's,
and pull/push rendered empty).
Anchor block extraction on the `export default`ed command, recurse into
locally-defined `const x = new Command()` groups mounted as subcommands, and
render nested sub-subcommands. Regenerated docs now show
`datatable migrate new/up/down` and `jobs pull/push` with their real
options.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6566,22 +6566,22 @@ Show all available wmill.yaml configuration options
|
||||
|
||||
### datatable
|
||||
|
||||
manage datatable migrations
|
||||
datatable related commands
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- \`datatable new <name:string>\` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- \`-d --datatable <datatable:string>\` - Target datatable (default: main)
|
||||
- \`datatable up\` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable down\` - datatable related commands
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable list\` - list all datatables in the workspace
|
||||
- \`--json\` - Output as JSON (for piping to jq)
|
||||
- \`datatable run <sql:string>\` - run a SQL query on a datatable
|
||||
- \`-n --name <name:string>\` - Datatable name (default: main)
|
||||
- \`-s --silent\` - Output only the final result as JSON. Useful for scripting.
|
||||
- \`datatable migrate\`
|
||||
- \`datatable migrate\` - manage datatable migrations
|
||||
- \`datatable migrate new <name:string>\` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- \`-d --datatable <datatable:string>\` - Target datatable (default: main)
|
||||
- \`datatable migrate up\` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable migrate down\` - roll back the most recent migration on every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable create [name:string]\` - register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>
|
||||
- \`--resource <resource:string>\` - Back the datatable with an existing postgresql resource path instead of the instance database
|
||||
- \`--force\` - Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)
|
||||
@@ -6850,19 +6850,18 @@ Manage jobs (list, inspect, cancel)
|
||||
|
||||
### jobs
|
||||
|
||||
Pull completed and queued jobs from workspace
|
||||
|
||||
**Arguments:** \`[workspace:string]\`
|
||||
|
||||
**Options:**
|
||||
- \`-c, --completed-output <file:string>\` - Completed jobs output file (default: completed_jobs.json)
|
||||
- \`-q, --queued-output <file:string>\` - Queued jobs output file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before export
|
||||
Manage jobs (import/export)
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- \`jobs pull\`
|
||||
- \`jobs push\`
|
||||
- \`jobs pull [workspace:string]\` - Pull completed and queued jobs from workspace
|
||||
- \`-c, --completed-output <file:string>\` - Completed jobs output file (default: completed_jobs.json)
|
||||
- \`-q, --queued-output <file:string>\` - Queued jobs output file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before export
|
||||
- \`jobs push [workspace:string]\` - Push completed and queued jobs to workspace
|
||||
- \`-c, --completed-file <file:string>\` - Completed jobs input file (default: completed_jobs.json)
|
||||
- \`-q, --queued-file <file:string>\` - Queued jobs input file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before import
|
||||
|
||||
### lint
|
||||
|
||||
|
||||
@@ -68,22 +68,22 @@ Show all available wmill.yaml configuration options
|
||||
|
||||
### datatable
|
||||
|
||||
manage datatable migrations
|
||||
datatable related commands
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- `datatable new <name:string>` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- `-d --datatable <datatable:string>` - Target datatable (default: main)
|
||||
- `datatable up` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable down` - datatable related commands
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable list` - list all datatables in the workspace
|
||||
- `--json` - Output as JSON (for piping to jq)
|
||||
- `datatable run <sql:string>` - run a SQL query on a datatable
|
||||
- `-n --name <name:string>` - Datatable name (default: main)
|
||||
- `-s --silent` - Output only the final result as JSON. Useful for scripting.
|
||||
- `datatable migrate`
|
||||
- `datatable migrate` - manage datatable migrations
|
||||
- `datatable migrate new <name:string>` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- `-d --datatable <datatable:string>` - Target datatable (default: main)
|
||||
- `datatable migrate up` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable migrate down` - roll back the most recent migration on every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable create [name:string]` - register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>
|
||||
- `--resource <resource:string>` - Back the datatable with an existing postgresql resource path instead of the instance database
|
||||
- `--force` - Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)
|
||||
@@ -352,19 +352,18 @@ Manage jobs (list, inspect, cancel)
|
||||
|
||||
### jobs
|
||||
|
||||
Pull completed and queued jobs from workspace
|
||||
|
||||
**Arguments:** `[workspace:string]`
|
||||
|
||||
**Options:**
|
||||
- `-c, --completed-output <file:string>` - Completed jobs output file (default: completed_jobs.json)
|
||||
- `-q, --queued-output <file:string>` - Queued jobs output file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before export
|
||||
Manage jobs (import/export)
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- `jobs pull`
|
||||
- `jobs push`
|
||||
- `jobs pull [workspace:string]` - Pull completed and queued jobs from workspace
|
||||
- `-c, --completed-output <file:string>` - Completed jobs output file (default: completed_jobs.json)
|
||||
- `-q, --queued-output <file:string>` - Queued jobs output file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before export
|
||||
- `jobs push [workspace:string]` - Push completed and queued jobs to workspace
|
||||
- `-c, --completed-file <file:string>` - Completed jobs input file (default: completed_jobs.json)
|
||||
- `-q, --queued-file <file:string>` - Queued jobs input file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before import
|
||||
|
||||
### lint
|
||||
|
||||
|
||||
@@ -2736,22 +2736,22 @@ Show all available wmill.yaml configuration options
|
||||
|
||||
### datatable
|
||||
|
||||
manage datatable migrations
|
||||
datatable related commands
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- \`datatable new <name:string>\` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- \`-d --datatable <datatable:string>\` - Target datatable (default: main)
|
||||
- \`datatable up\` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable down\` - datatable related commands
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable list\` - list all datatables in the workspace
|
||||
- \`--json\` - Output as JSON (for piping to jq)
|
||||
- \`datatable run <sql:string>\` - run a SQL query on a datatable
|
||||
- \`-n --name <name:string>\` - Datatable name (default: main)
|
||||
- \`-s --silent\` - Output only the final result as JSON. Useful for scripting.
|
||||
- \`datatable migrate\`
|
||||
- \`datatable migrate\` - manage datatable migrations
|
||||
- \`datatable migrate new <name:string>\` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- \`-d --datatable <datatable:string>\` - Target datatable (default: main)
|
||||
- \`datatable migrate up\` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable migrate down\` - roll back the most recent migration on every datatable (or one via --datatable)
|
||||
- \`-d --datatable <datatable:string>\` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- \`datatable create [name:string]\` - register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>
|
||||
- \`--resource <resource:string>\` - Back the datatable with an existing postgresql resource path instead of the instance database
|
||||
- \`--force\` - Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)
|
||||
@@ -3020,19 +3020,18 @@ Manage jobs (list, inspect, cancel)
|
||||
|
||||
### jobs
|
||||
|
||||
Pull completed and queued jobs from workspace
|
||||
|
||||
**Arguments:** \`[workspace:string]\`
|
||||
|
||||
**Options:**
|
||||
- \`-c, --completed-output <file:string>\` - Completed jobs output file (default: completed_jobs.json)
|
||||
- \`-q, --queued-output <file:string>\` - Queued jobs output file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before export
|
||||
Manage jobs (import/export)
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- \`jobs pull\`
|
||||
- \`jobs push\`
|
||||
- \`jobs pull [workspace:string]\` - Pull completed and queued jobs from workspace
|
||||
- \`-c, --completed-output <file:string>\` - Completed jobs output file (default: completed_jobs.json)
|
||||
- \`-q, --queued-output <file:string>\` - Queued jobs output file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before export
|
||||
- \`jobs push [workspace:string]\` - Push completed and queued jobs to workspace
|
||||
- \`-c, --completed-file <file:string>\` - Completed jobs input file (default: completed_jobs.json)
|
||||
- \`-q, --queued-file <file:string>\` - Queued jobs input file (default: queued_jobs.json)
|
||||
- \`--skip-worker-check\` - Skip checking for active workers before import
|
||||
|
||||
### lint
|
||||
|
||||
|
||||
@@ -73,22 +73,22 @@ Show all available wmill.yaml configuration options
|
||||
|
||||
### datatable
|
||||
|
||||
manage datatable migrations
|
||||
datatable related commands
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- `datatable new <name:string>` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- `-d --datatable <datatable:string>` - Target datatable (default: main)
|
||||
- `datatable up` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable down` - datatable related commands
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable list` - list all datatables in the workspace
|
||||
- `--json` - Output as JSON (for piping to jq)
|
||||
- `datatable run <sql:string>` - run a SQL query on a datatable
|
||||
- `-n --name <name:string>` - Datatable name (default: main)
|
||||
- `-s --silent` - Output only the final result as JSON. Useful for scripting.
|
||||
- `datatable migrate`
|
||||
- `datatable migrate` - manage datatable migrations
|
||||
- `datatable migrate new <name:string>` - scaffold a new migration (.up.sql / .down.sql files)
|
||||
- `-d --datatable <datatable:string>` - Target datatable (default: main)
|
||||
- `datatable migrate up` - apply all pending migrations to every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable migrate down` - roll back the most recent migration on every datatable (or one via --datatable)
|
||||
- `-d --datatable <datatable:string>` - Target a specific datatable (default: all datatables in the workspace)
|
||||
- `datatable create [name:string]` - register a datatable database in the workspace (default: instance-backed 'main') so scripts can use datatable://<name>
|
||||
- `--resource <resource:string>` - Back the datatable with an existing postgresql resource path instead of the instance database
|
||||
- `--force` - Allow adding to a workspace that already has datatables (fork metadata on existing ones is not preserved)
|
||||
@@ -357,19 +357,18 @@ Manage jobs (list, inspect, cancel)
|
||||
|
||||
### jobs
|
||||
|
||||
Pull completed and queued jobs from workspace
|
||||
|
||||
**Arguments:** `[workspace:string]`
|
||||
|
||||
**Options:**
|
||||
- `-c, --completed-output <file:string>` - Completed jobs output file (default: completed_jobs.json)
|
||||
- `-q, --queued-output <file:string>` - Queued jobs output file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before export
|
||||
Manage jobs (import/export)
|
||||
|
||||
**Subcommands:**
|
||||
|
||||
- `jobs pull`
|
||||
- `jobs push`
|
||||
- `jobs pull [workspace:string]` - Pull completed and queued jobs from workspace
|
||||
- `-c, --completed-output <file:string>` - Completed jobs output file (default: completed_jobs.json)
|
||||
- `-q, --queued-output <file:string>` - Queued jobs output file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before export
|
||||
- `jobs push [workspace:string]` - Push completed and queued jobs to workspace
|
||||
- `-c, --completed-file <file:string>` - Completed jobs input file (default: completed_jobs.json)
|
||||
- `-q, --queued-file <file:string>` - Queued jobs input file (default: queued_jobs.json)
|
||||
- `--skip-worker-check` - Skip checking for active workers before import
|
||||
|
||||
### lint
|
||||
|
||||
|
||||
+76
-10
@@ -340,13 +340,54 @@ def extract_description(section: str) -> str | None:
|
||||
return ''.join(_unquote_js_string(p) for p in parts).strip() or None
|
||||
|
||||
|
||||
def parse_command_block(content: str, file_path: Path | None = None) -> dict:
|
||||
def extract_named_command_block(content: str, var_name: str) -> str | None:
|
||||
"""Return the chained-call body of `const <var_name> = new Command() ...`,
|
||||
from just after `new Command()` up to the next top-level statement.
|
||||
|
||||
Returns None when the var isn't a *direct* `new Command()` (e.g. it's wrapped
|
||||
in a helper call like `auditListOptions(new Command()...)`), so callers can
|
||||
fall back to a looser match.
|
||||
"""
|
||||
m = re.search(
|
||||
r'const\s+' + re.escape(var_name) + r'\s*=\s*new\s+Command\(\)'
|
||||
r'([\s\S]*?)(?=\n(?:const|let|var|async|function|export)\b)',
|
||||
content,
|
||||
)
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def extract_exported_command_block(content: str) -> str | None:
|
||||
"""Return the chained-call body of the command that is `export default`ed.
|
||||
|
||||
A command file may define helper `new Command()` groups (assigned to local
|
||||
consts and mounted as nested subcommands via `.command("x", localCmd)`)
|
||||
*before* the exported command. Anchoring on the first `new Command()` in the
|
||||
file would merge those helpers into the top-level command, so resolve the
|
||||
exported variable first and only then fall back to the first `new Command()`
|
||||
(which covers inline/wrapped exports).
|
||||
"""
|
||||
export_match = re.search(r'export\s+default\s+(\w+)\s*;', content)
|
||||
if export_match:
|
||||
block = extract_named_command_block(content, export_match.group(1))
|
||||
if block is not None:
|
||||
return block
|
||||
command_match = re.search(
|
||||
r'(?:const\s+command\s*=\s*)?new\s+Command\(\)([\s\S]*?)(?=export\s+default)',
|
||||
content,
|
||||
)
|
||||
return command_match.group(1) if command_match else None
|
||||
|
||||
|
||||
def parse_command_block(
|
||||
content: str, file_path: Path | None = None, block: str | None = None
|
||||
) -> dict:
|
||||
"""
|
||||
Parse a Cliffy Command() definition block and extract metadata.
|
||||
Returns a dict with: description, options, subcommands, arguments, alias
|
||||
|
||||
If file_path is provided, imported subcommands will be resolved by parsing
|
||||
the imported files.
|
||||
the imported files. `block` may be passed to parse a specific pre-extracted
|
||||
command body (used to recurse into locally-defined nested command groups).
|
||||
"""
|
||||
result = {
|
||||
'description': '',
|
||||
@@ -357,15 +398,11 @@ def parse_command_block(content: str, file_path: Path | None = None) -> dict:
|
||||
}
|
||||
|
||||
# Find the command block
|
||||
command_match = re.search(
|
||||
r'(?:const\s+command\s*=\s*)?new\s+Command\(\)([\s\S]*?)(?=export\s+default)',
|
||||
content
|
||||
)
|
||||
if not command_match:
|
||||
if block is None:
|
||||
block = extract_exported_command_block(content)
|
||||
if block is None:
|
||||
return result
|
||||
|
||||
block = command_match.group(1)
|
||||
|
||||
# Find where subcommands start
|
||||
first_subcommand_pos = block.find('.command(')
|
||||
if first_subcommand_pos == -1:
|
||||
@@ -451,12 +488,31 @@ def parse_command_block(content: str, file_path: Path | None = None) -> dict:
|
||||
'name': cmd_name,
|
||||
'description': imported_cmd.get('description', ''),
|
||||
'arguments': imported_cmd.get('arguments', ''),
|
||||
'options': imported_cmd.get('options', [])
|
||||
'options': imported_cmd.get('options', []),
|
||||
'subcommands': imported_cmd.get('subcommands', []),
|
||||
})
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f" Warning: Could not parse imported command {second_arg}: {e}")
|
||||
cmd_desc = ''
|
||||
elif second_arg and re.search(
|
||||
r'const\s+' + re.escape(second_arg) + r'\s*=\s*new\s+Command\(\)', content
|
||||
):
|
||||
# Locally-defined command group mounted as a subcommand
|
||||
# (e.g. `.command("migrate", migrateCommand)`): recurse into its
|
||||
# definition so its own subcommands/options are captured.
|
||||
nested_block = extract_named_command_block(content, second_arg)
|
||||
if nested_block is not None:
|
||||
nested = parse_command_block(content, file_path, block=nested_block)
|
||||
result['subcommands'].append({
|
||||
'name': cmd_name,
|
||||
'description': nested.get('description', ''),
|
||||
'arguments': nested.get('arguments', ''),
|
||||
'options': nested.get('options', []),
|
||||
'subcommands': nested.get('subcommands', []),
|
||||
})
|
||||
continue
|
||||
cmd_desc = ''
|
||||
else:
|
||||
cmd_desc = ''
|
||||
|
||||
@@ -628,6 +684,16 @@ def generate_cli_commands_markdown(cli_data: dict) -> str:
|
||||
for opt in sub['options']:
|
||||
md += f" - `{opt['flag']}` - {opt['description']}\n"
|
||||
|
||||
# Nested sub-subcommands (e.g. `datatable migrate new`)
|
||||
for subsub in sub.get('subcommands', []):
|
||||
ss_args = f" {subsub['arguments']}" if subsub.get('arguments') else ""
|
||||
md += f" - `{cmd['name']} {sub_name} {subsub['name']}{ss_args}`"
|
||||
if subsub.get('description'):
|
||||
md += f" - {subsub['description']}"
|
||||
md += "\n"
|
||||
for opt in subsub.get('options', []):
|
||||
md += f" - `{opt['flag']}` - {opt['description']}\n"
|
||||
|
||||
md += "\n"
|
||||
|
||||
return md
|
||||
|
||||
Reference in New Issue
Block a user