flowsh-cli 0.3.0__tar.gz → 0.4.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.3.0 → flowsh_cli-0.4.0}/PKG-INFO +7 -3
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/README.md +6 -2
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/pyproject.toml +1 -1
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/src/flowsh_cli/__init__.py +1 -1
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/src/flowsh_cli/models.py +32 -2
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/src/flowsh_cli/render.py +20 -5
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/src/flowsh_cli/__main__.py +0 -0
- {flowsh_cli-0.3.0 → flowsh_cli-0.4.0}/src/flowsh_cli/cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flowsh-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.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
|
|
@@ -38,13 +38,15 @@ workflows:
|
|
|
38
38
|
- type: agent
|
|
39
39
|
name: Ask OpenCode
|
|
40
40
|
agent: general
|
|
41
|
+
model: openai/gpt-5
|
|
42
|
+
command: review
|
|
41
43
|
prompt: |
|
|
42
44
|
Summarize the current repository state.
|
|
43
45
|
```
|
|
44
46
|
|
|
45
47
|
Supported step types are only `vars`, `bash`, and `agent`.
|
|
46
48
|
|
|
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 `-`.
|
|
49
|
+
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 `-`. Agent `model` values are passed through to OpenCode, so provider/model IDs such as `openai/gpt-5` are valid. Agent `command` values map to OpenCode `--command`; the prompt remains the message/arguments after `--`.
|
|
48
50
|
|
|
49
51
|
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
52
|
|
|
@@ -59,6 +61,8 @@ Agent prompts are literal by default. Set `expandPrompt: true` on an `agent` ste
|
|
|
59
61
|
|
|
60
62
|
`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
63
|
|
|
64
|
+
Set `dangerouslySkipPermissions: true` on an `agent` step only when the generated harness should pass OpenCode `--dangerously-skip-permissions`. The flag is false by default, accepts the YAML alias `dangerously-skip-permissions`, and auto-approves permissions that are not explicitly denied. Treat it as security-sensitive and avoid it for untrusted workflows.
|
|
65
|
+
|
|
62
66
|
Harness paths are derived from workflow ids. `wf_example` writes `.harness/example.sh`.
|
|
63
67
|
|
|
64
68
|
## Commands
|
|
@@ -130,7 +134,7 @@ Generated harnesses are also non-interactive. `harness.sh --dry-run` exits `0` a
|
|
|
130
134
|
|
|
131
135
|
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.
|
|
132
136
|
|
|
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
|
|
137
|
+
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` with optional `--agent <agent>`, `--model <provider/model>`, `--command <command>`, and `--dangerously-skip-permissions` flags before `-- <prompt>`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
134
138
|
|
|
135
139
|
## Development
|
|
136
140
|
|
|
@@ -22,13 +22,15 @@ workflows:
|
|
|
22
22
|
- type: agent
|
|
23
23
|
name: Ask OpenCode
|
|
24
24
|
agent: general
|
|
25
|
+
model: openai/gpt-5
|
|
26
|
+
command: review
|
|
25
27
|
prompt: |
|
|
26
28
|
Summarize the current repository state.
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
Supported step types are only `vars`, `bash`, and `agent`.
|
|
30
32
|
|
|
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 `-`.
|
|
33
|
+
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 `-`. Agent `model` values are passed through to OpenCode, so provider/model IDs such as `openai/gpt-5` are valid. Agent `command` values map to OpenCode `--command`; the prompt remains the message/arguments after `--`.
|
|
32
34
|
|
|
33
35
|
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
36
|
|
|
@@ -43,6 +45,8 @@ Agent prompts are literal by default. Set `expandPrompt: true` on an `agent` ste
|
|
|
43
45
|
|
|
44
46
|
`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
47
|
|
|
48
|
+
Set `dangerouslySkipPermissions: true` on an `agent` step only when the generated harness should pass OpenCode `--dangerously-skip-permissions`. The flag is false by default, accepts the YAML alias `dangerously-skip-permissions`, and auto-approves permissions that are not explicitly denied. Treat it as security-sensitive and avoid it for untrusted workflows.
|
|
49
|
+
|
|
46
50
|
Harness paths are derived from workflow ids. `wf_example` writes `.harness/example.sh`.
|
|
47
51
|
|
|
48
52
|
## Commands
|
|
@@ -114,7 +118,7 @@ Generated harnesses are also non-interactive. `harness.sh --dry-run` exits `0` a
|
|
|
114
118
|
|
|
115
119
|
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.
|
|
116
120
|
|
|
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
|
|
121
|
+
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` with optional `--agent <agent>`, `--model <provider/model>`, `--command <command>`, and `--dangerously-skip-permissions` flags before `-- <prompt>`, so dash-prefixed prompts are message content rather than OpenCode flags. Agent steps fail with a clear error if `opencode` is not on `PATH`.
|
|
118
122
|
|
|
119
123
|
## Development
|
|
120
124
|
|
|
@@ -7,7 +7,15 @@ from pathlib import Path
|
|
|
7
7
|
from typing import Annotated, Literal
|
|
8
8
|
|
|
9
9
|
import yaml
|
|
10
|
-
from pydantic import
|
|
10
|
+
from pydantic import (
|
|
11
|
+
AliasChoices,
|
|
12
|
+
BaseModel,
|
|
13
|
+
ConfigDict,
|
|
14
|
+
Field,
|
|
15
|
+
ValidationError,
|
|
16
|
+
field_validator,
|
|
17
|
+
model_validator,
|
|
18
|
+
)
|
|
11
19
|
|
|
12
20
|
MAX_WORKFLOW_YAML_BYTES = 1_048_576
|
|
13
21
|
|
|
@@ -67,9 +75,31 @@ class AgentStep(BaseStep):
|
|
|
67
75
|
type: Literal["agent"]
|
|
68
76
|
prompt: str
|
|
69
77
|
agent: str | None = None
|
|
78
|
+
model: str | None = None
|
|
79
|
+
command: str | None = None
|
|
80
|
+
dangerouslySkipPermissions: bool = Field(
|
|
81
|
+
default=False,
|
|
82
|
+
validation_alias=AliasChoices(
|
|
83
|
+
"dangerouslySkipPermissions",
|
|
84
|
+
"dangerously-skip-permissions",
|
|
85
|
+
),
|
|
86
|
+
)
|
|
70
87
|
expandPrompt: bool = False
|
|
71
88
|
|
|
72
|
-
@
|
|
89
|
+
@model_validator(mode="before")
|
|
90
|
+
@classmethod
|
|
91
|
+
def reject_ambiguous_dangerous_aliases(cls, data: object) -> object:
|
|
92
|
+
if (
|
|
93
|
+
isinstance(data, Mapping)
|
|
94
|
+
and "dangerouslySkipPermissions" in data
|
|
95
|
+
and "dangerously-skip-permissions" in data
|
|
96
|
+
):
|
|
97
|
+
raise ValueError(
|
|
98
|
+
"dangerouslySkipPermissions and dangerously-skip-permissions must not both be set"
|
|
99
|
+
)
|
|
100
|
+
return data
|
|
101
|
+
|
|
102
|
+
@field_validator("prompt", "agent", "model", "command")
|
|
73
103
|
@classmethod
|
|
74
104
|
def validate_strings(cls, value: str | None) -> str | None:
|
|
75
105
|
if value is not None and value.strip() == "":
|
|
@@ -174,11 +174,23 @@ def render_harness(workflow: Workflow) -> str:
|
|
|
174
174
|
"run_agent() {",
|
|
175
175
|
' local prompt="$1"',
|
|
176
176
|
' local agent="${2:-}"',
|
|
177
|
+
' local model="${3:-}"',
|
|
178
|
+
' local command="${4:-}"',
|
|
179
|
+
' local dangerously_skip_permissions="${5:-false}"',
|
|
177
180
|
"",
|
|
178
181
|
" local cmd=(opencode run --format json)",
|
|
179
182
|
' if [[ -n "$agent" ]]; then',
|
|
180
183
|
' cmd+=(--agent "$agent")',
|
|
181
184
|
" fi",
|
|
185
|
+
' if [[ -n "$model" ]]; then',
|
|
186
|
+
' cmd+=(--model "$model")',
|
|
187
|
+
" fi",
|
|
188
|
+
' if [[ -n "$command" ]]; then',
|
|
189
|
+
' cmd+=(--command "$command")',
|
|
190
|
+
" fi",
|
|
191
|
+
' if [[ "$dangerously_skip_permissions" == true ]]; then',
|
|
192
|
+
" cmd+=(--dangerously-skip-permissions)",
|
|
193
|
+
" fi",
|
|
182
194
|
"",
|
|
183
195
|
' if [[ "$DRY_RUN" == true ]]; then',
|
|
184
196
|
' log INFO "[DRY-RUN] would run: $(printf \'%q \' "${cmd[@]}") (with prompt)"',
|
|
@@ -255,11 +267,14 @@ def render_step(index: int, step: Step, used_function_names: set[str] | None = N
|
|
|
255
267
|
" )",
|
|
256
268
|
]
|
|
257
269
|
)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
else
|
|
262
|
-
|
|
270
|
+
lines.append(f" local agent={bash_quote(step.agent or '')}")
|
|
271
|
+
lines.append(f" local model={bash_quote(step.model or '')}")
|
|
272
|
+
lines.append(f" local command={bash_quote(step.command or '')}")
|
|
273
|
+
dangerous_skip_permissions = "true" if step.dangerouslySkipPermissions else "false"
|
|
274
|
+
lines.append(f" local dangerously_skip_permissions={dangerous_skip_permissions}")
|
|
275
|
+
lines.append(
|
|
276
|
+
' run_agent "$prompt" "$agent" "$model" "$command" "$dangerously_skip_permissions"'
|
|
277
|
+
)
|
|
263
278
|
else:
|
|
264
279
|
raise AssertionError(f"Unsupported step type: {step}")
|
|
265
280
|
|
|
File without changes
|
|
File without changes
|