flowsh-cli 0.2.1__tar.gz → 0.3.0__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.
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/PKG-INFO +20 -2
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/README.md +19 -1
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/pyproject.toml +1 -2
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/src/flowsh_cli/__init__.py +1 -1
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/src/flowsh_cli/cli.py +19 -1
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/src/flowsh_cli/models.py +9 -0
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/src/flowsh_cli/render.py +2 -1
- {flowsh_cli-0.2.1 → flowsh_cli-0.3.0}/src/flowsh_cli/__main__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowsh-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Generate Bash harness scripts from workflow YAML files.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.11
|
|
@@ -46,6 +46,19 @@ Supported step types are only `vars`, `bash`, and `agent`.
|
|
|
46
46
|
|
|
47
47
|
The input path must be a regular file no larger than 1 MiB. The input file must be valid UTF-8, non-empty YAML with a mapping root, no duplicate mapping keys, and no YAML aliases. Workflow and step names are single-line labels. Executable fields reject unsafe control bytes while allowing normal newlines and tabs. `vars` keys must be uppercase shell variable names, and `agent` names may contain only letters, digits, `_`, and `-`.
|
|
48
48
|
|
|
49
|
+
Agent prompts are literal by default. Set `expandPrompt: true` on an `agent` step only when the prompt should be expanded by Bash at harness runtime, for example to insert values exported by earlier `vars` steps:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
- type: agent
|
|
53
|
+
name: Fix captured issue
|
|
54
|
+
agent: general
|
|
55
|
+
expandPrompt: true
|
|
56
|
+
prompt: |
|
|
57
|
+
Follow issue #$ISSUE_NUMBER.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`expandPrompt: true` is a security-sensitive opt-in: Bash also performs command substitution such as `$(...)` and backticks in the prompt body before OpenCode receives it. Keep it disabled for prompts that contain shell examples or untrusted content.
|
|
61
|
+
|
|
49
62
|
Harness paths are derived from workflow ids. `wf_example` writes `.harness/example.sh`.
|
|
50
63
|
|
|
51
64
|
## Commands
|
|
@@ -65,6 +78,9 @@ uvx flowsh-cli .made/workflows.yml --force
|
|
|
65
78
|
|
|
66
79
|
# Show version
|
|
67
80
|
uvx flowsh-cli --version
|
|
81
|
+
|
|
82
|
+
# Show the workflow YAML schema
|
|
83
|
+
uvx flowsh-cli --schema
|
|
68
84
|
```
|
|
69
85
|
|
|
70
86
|
You can also run it via `uv run flowsh-cli` if installed locally.
|
|
@@ -88,6 +104,7 @@ Options:
|
|
|
88
104
|
--dry-run Print planned output paths without writing scripts.
|
|
89
105
|
--force Overwrite existing files. Without this, existing files cause a failure.
|
|
90
106
|
--version Show the flowsh-cli version and exit.
|
|
107
|
+
--schema Show the workflow YAML schema and exit.
|
|
91
108
|
--help Show this message and exit.
|
|
92
109
|
```
|
|
93
110
|
|
|
@@ -100,6 +117,7 @@ Exit codes:
|
|
|
100
117
|
|---|---:|---|---|
|
|
101
118
|
| `--help` | `0` | Help text | Empty |
|
|
102
119
|
| `--version` | `0` | `flowsh-cli <version>` | Empty |
|
|
120
|
+
| `--schema` | `0` | Workflow schema as YAML-formatted JSON Schema | Empty |
|
|
103
121
|
| Valid generation | `0` | One `Wrote <path>` line per harness | Empty |
|
|
104
122
|
| Valid `--dry-run` | `0` | One `DRY-RUN would write <path>` line per selected workflow | Empty |
|
|
105
123
|
| Missing required CLI argument | `2` | Empty | Typer usage error |
|
|
@@ -112,7 +130,7 @@ Generated harnesses are also non-interactive. `harness.sh --dry-run` exits `0` a
|
|
|
112
130
|
|
|
113
131
|
Generated harnesses are written with owner-only executable permissions and refuse to overwrite existing paths unless `--force` is passed. Multi-workflow generation preflights overwrite conflicts before writing any harness. `--force` replaces regular harness files and harness-file symlinks, but never replaces a directory at a harness file path. The `.harness` output directory must be a real directory, not a symlink or file. Harness dry runs do not create log files or directories. Real harness logs go to `.flowsh/logs` by default with owner-private directory and file permissions. Set `FLOWSH_LOG_DIR` when running a harness to use another local relative log directory; absolute paths, `..` path segments, symlinked path components, and non-directory log paths are refused. Logging setup and write failures fail the harness instead of being silently ignored.
|
|
114
132
|
|
|
115
|
-
Generated `bash` and `vars` bodies run with `bash -euo pipefail`, so command failures stop the workflow instead of being masked by later successful commands. Captured `vars` values are exported for later `bash` steps. `agent` steps invoke only `opencode run --format json -- <prompt>` with optional `--agent <agent>` before `--`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
133
|
+
Generated `bash` and `vars` bodies run with `bash -euo pipefail`, so command failures stop the workflow instead of being masked by later successful commands. Captured `vars` values are exported for later `bash` steps. `agent` prompt heredocs are quoted by default and unquoted only when `expandPrompt: true` is set. `agent` steps invoke only `opencode run --format json -- <prompt>` with optional `--agent <agent>` before `--`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
116
134
|
|
|
117
135
|
## Development
|
|
118
136
|
|
|
@@ -30,6 +30,19 @@ Supported step types are only `vars`, `bash`, and `agent`.
|
|
|
30
30
|
|
|
31
31
|
The input path must be a regular file no larger than 1 MiB. The input file must be valid UTF-8, non-empty YAML with a mapping root, no duplicate mapping keys, and no YAML aliases. Workflow and step names are single-line labels. Executable fields reject unsafe control bytes while allowing normal newlines and tabs. `vars` keys must be uppercase shell variable names, and `agent` names may contain only letters, digits, `_`, and `-`.
|
|
32
32
|
|
|
33
|
+
Agent prompts are literal by default. Set `expandPrompt: true` on an `agent` step only when the prompt should be expanded by Bash at harness runtime, for example to insert values exported by earlier `vars` steps:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
- type: agent
|
|
37
|
+
name: Fix captured issue
|
|
38
|
+
agent: general
|
|
39
|
+
expandPrompt: true
|
|
40
|
+
prompt: |
|
|
41
|
+
Follow issue #$ISSUE_NUMBER.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`expandPrompt: true` is a security-sensitive opt-in: Bash also performs command substitution such as `$(...)` and backticks in the prompt body before OpenCode receives it. Keep it disabled for prompts that contain shell examples or untrusted content.
|
|
45
|
+
|
|
33
46
|
Harness paths are derived from workflow ids. `wf_example` writes `.harness/example.sh`.
|
|
34
47
|
|
|
35
48
|
## Commands
|
|
@@ -49,6 +62,9 @@ uvx flowsh-cli .made/workflows.yml --force
|
|
|
49
62
|
|
|
50
63
|
# Show version
|
|
51
64
|
uvx flowsh-cli --version
|
|
65
|
+
|
|
66
|
+
# Show the workflow YAML schema
|
|
67
|
+
uvx flowsh-cli --schema
|
|
52
68
|
```
|
|
53
69
|
|
|
54
70
|
You can also run it via `uv run flowsh-cli` if installed locally.
|
|
@@ -72,6 +88,7 @@ Options:
|
|
|
72
88
|
--dry-run Print planned output paths without writing scripts.
|
|
73
89
|
--force Overwrite existing files. Without this, existing files cause a failure.
|
|
74
90
|
--version Show the flowsh-cli version and exit.
|
|
91
|
+
--schema Show the workflow YAML schema and exit.
|
|
75
92
|
--help Show this message and exit.
|
|
76
93
|
```
|
|
77
94
|
|
|
@@ -84,6 +101,7 @@ Exit codes:
|
|
|
84
101
|
|---|---:|---|---|
|
|
85
102
|
| `--help` | `0` | Help text | Empty |
|
|
86
103
|
| `--version` | `0` | `flowsh-cli <version>` | Empty |
|
|
104
|
+
| `--schema` | `0` | Workflow schema as YAML-formatted JSON Schema | Empty |
|
|
87
105
|
| Valid generation | `0` | One `Wrote <path>` line per harness | Empty |
|
|
88
106
|
| Valid `--dry-run` | `0` | One `DRY-RUN would write <path>` line per selected workflow | Empty |
|
|
89
107
|
| Missing required CLI argument | `2` | Empty | Typer usage error |
|
|
@@ -96,7 +114,7 @@ Generated harnesses are also non-interactive. `harness.sh --dry-run` exits `0` a
|
|
|
96
114
|
|
|
97
115
|
Generated harnesses are written with owner-only executable permissions and refuse to overwrite existing paths unless `--force` is passed. Multi-workflow generation preflights overwrite conflicts before writing any harness. `--force` replaces regular harness files and harness-file symlinks, but never replaces a directory at a harness file path. The `.harness` output directory must be a real directory, not a symlink or file. Harness dry runs do not create log files or directories. Real harness logs go to `.flowsh/logs` by default with owner-private directory and file permissions. Set `FLOWSH_LOG_DIR` when running a harness to use another local relative log directory; absolute paths, `..` path segments, symlinked path components, and non-directory log paths are refused. Logging setup and write failures fail the harness instead of being silently ignored.
|
|
98
116
|
|
|
99
|
-
Generated `bash` and `vars` bodies run with `bash -euo pipefail`, so command failures stop the workflow instead of being masked by later successful commands. Captured `vars` values are exported for later `bash` steps. `agent` steps invoke only `opencode run --format json -- <prompt>` with optional `--agent <agent>` before `--`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
117
|
+
Generated `bash` and `vars` bodies run with `bash -euo pipefail`, so command failures stop the workflow instead of being masked by later successful commands. Captured `vars` values are exported for later `bash` steps. `agent` prompt heredocs are quoted by default and unquoted only when `expandPrompt: true` is set. `agent` steps invoke only `opencode run --format json -- <prompt>` with optional `--agent <agent>` before `--`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
100
118
|
|
|
101
119
|
## Development
|
|
102
120
|
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flowsh-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Generate Bash harness scripts from workflow YAML files."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -39,7 +39,6 @@ testpaths = ["tests"]
|
|
|
39
39
|
[tool.ruff]
|
|
40
40
|
line-length = 100
|
|
41
41
|
target-version = "py311"
|
|
42
|
-
exclude = ["scripts/"]
|
|
43
42
|
|
|
44
43
|
[tool.ruff.lint]
|
|
45
44
|
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
@@ -11,7 +11,7 @@ from typing import Annotated
|
|
|
11
11
|
import typer
|
|
12
12
|
|
|
13
13
|
from flowsh_cli import __version__
|
|
14
|
-
from flowsh_cli.models import Workflow, WorkflowParseError, parse_workflows
|
|
14
|
+
from flowsh_cli.models import Workflow, WorkflowParseError, parse_workflows, workflow_schema_yaml
|
|
15
15
|
from flowsh_cli.render import harness_path, render_harness
|
|
16
16
|
|
|
17
17
|
app = typer.Typer(
|
|
@@ -62,10 +62,20 @@ def generate(
|
|
|
62
62
|
is_eager=True,
|
|
63
63
|
),
|
|
64
64
|
] = False,
|
|
65
|
+
schema: Annotated[
|
|
66
|
+
bool,
|
|
67
|
+
typer.Option(
|
|
68
|
+
"--schema",
|
|
69
|
+
callback=lambda value: print_schema(value),
|
|
70
|
+
help="Show the workflow YAML schema and exit.",
|
|
71
|
+
is_eager=True,
|
|
72
|
+
),
|
|
73
|
+
] = False,
|
|
65
74
|
) -> None:
|
|
66
75
|
"""Generate Bash harnesses from workflow YAML."""
|
|
67
76
|
|
|
68
77
|
_ = version
|
|
78
|
+
_ = schema
|
|
69
79
|
|
|
70
80
|
try:
|
|
71
81
|
workflows = parse_workflows(workflow_yaml)
|
|
@@ -99,6 +109,14 @@ def print_version(value: bool) -> None:
|
|
|
99
109
|
raise typer.Exit
|
|
100
110
|
|
|
101
111
|
|
|
112
|
+
def print_schema(value: bool) -> None:
|
|
113
|
+
if not value:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
print(workflow_schema_yaml(), end="")
|
|
117
|
+
raise typer.Exit
|
|
118
|
+
|
|
119
|
+
|
|
102
120
|
def write_harnesses(workflows: list[Workflow], *, dry_run: bool, force: bool) -> None:
|
|
103
121
|
output_paths = [(workflow, harness_path(workflow)) for workflow in workflows]
|
|
104
122
|
|
|
@@ -67,6 +67,7 @@ class AgentStep(BaseStep):
|
|
|
67
67
|
type: Literal["agent"]
|
|
68
68
|
prompt: str
|
|
69
69
|
agent: str | None = None
|
|
70
|
+
expandPrompt: bool = False
|
|
70
71
|
|
|
71
72
|
@field_validator("prompt", "agent")
|
|
72
73
|
@classmethod
|
|
@@ -175,6 +176,14 @@ def parse_workflows(path: Path) -> list[Workflow]:
|
|
|
175
176
|
raise WorkflowParseError(format_validation_error(error)) from error
|
|
176
177
|
|
|
177
178
|
|
|
179
|
+
def workflow_schema_yaml() -> str:
|
|
180
|
+
return yaml.safe_dump(
|
|
181
|
+
WorkflowFile.model_json_schema(),
|
|
182
|
+
sort_keys=False,
|
|
183
|
+
allow_unicode=False,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
178
187
|
def format_validation_error(error: ValidationError) -> str:
|
|
179
188
|
messages: list[str] = []
|
|
180
189
|
for item in error.errors(include_url=False, include_input=False, include_context=False):
|
|
@@ -245,10 +245,11 @@ def render_step(index: int, step: Step, used_function_names: set[str] | None = N
|
|
|
245
245
|
)
|
|
246
246
|
elif isinstance(step, AgentStep):
|
|
247
247
|
delimiter = heredoc_delimiter("PROMPT", step.prompt)
|
|
248
|
+
heredoc = f"<<{delimiter}" if step.expandPrompt else f"<<'{delimiter}'"
|
|
248
249
|
lines.extend(
|
|
249
250
|
[
|
|
250
251
|
" local prompt",
|
|
251
|
-
f" prompt=$(cat
|
|
252
|
+
f" prompt=$(cat {heredoc}",
|
|
252
253
|
*step.prompt.splitlines(),
|
|
253
254
|
delimiter,
|
|
254
255
|
" )",
|
|
File without changes
|