hookstride-cli 0.2.1__tar.gz → 0.3.1__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.
@@ -0,0 +1,165 @@
1
+ Metadata-Version: 2.5
2
+ Name: hookstride-cli
3
+ Version: 0.3.1
4
+ Summary: Manage Hookstride projects and destinations, inspect webhook activity and billing.
5
+ License: Proprietary
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: click<9,>=8.1
8
+ Requires-Dist: httpx<1,>=0.28
9
+ Requires-Dist: prompt-toolkit<4,>=3.0.52
10
+ Requires-Dist: rich<15,>=14
11
+ Requires-Dist: typer<1,>=0.20
12
+ Description-Content-Type: text/markdown
13
+
14
+ # Hookstride CLI
15
+
16
+ Hookstride CLI lets you manage projects and webhook destinations, inspect delivery activity, and view billing records. It includes an interactive console with the same selected-project commands.
17
+
18
+ Version 0.3.1 adds signed test-event sending with an existing project's delivery API key, and optional delivery-status polling. Project and destination management remain available; billing and credential changes, delivery replay, and destructive operations remain unavailable.
19
+
20
+ ## Installation
21
+
22
+
23
+ Requires Python 3.11 or later.
24
+
25
+ ```bash
26
+ uv tool install hookstride-cli
27
+ ```
28
+
29
+ Alternatively, use `pipx install hookstride-cli`.
30
+
31
+ ```bash
32
+ hookstride --version
33
+ hookstride status
34
+ hookstride console
35
+ ```
36
+
37
+ Upgrade an existing installation with `uv tool upgrade hookstride-cli`.
38
+
39
+ ## Authentication
40
+
41
+ Authenticated commands require a **Control API token** (`whrctl_`), available from your Hookstride dashboard. Project delivery API keys (`whrk_`) do not grant CLI access.
42
+
43
+ In an interactive console, run `auth login` and enter the token at the hidden prompt:
44
+
45
+ ```bash
46
+ hookstride console
47
+ ```
48
+
49
+ For one-off commands, set `HOOKSTRIDE_CONTROL_TOKEN` in your shell without entering it on the command line:
50
+
51
+ ```bash
52
+ read -rs "HOOKSTRIDE_CONTROL_TOKEN?Control token: "
53
+ echo
54
+ export HOOKSTRIDE_CONTROL_TOKEN
55
+ hookstride auth status
56
+ ```
57
+
58
+ The `read` example above works in **zsh**. In Bash, use `read -rs -p "Control token: " HOOKSTRIDE_CONTROL_TOKEN` followed by `echo` and `export HOOKSTRIDE_CONTROL_TOKEN`.
59
+
60
+ Tokens entered through `auth login` are retained only for the interactive console session. The CLI does not write tokens to its settings file.
61
+
62
+ ## Commands
63
+
64
+ ```bash
65
+ hookstride status
66
+ hookstride auth status
67
+ hookstride projects list
68
+ hookstride projects use PROJECT_UUID
69
+ hookstride projects create --account ACCOUNT_UUID --name "Staging" --slug staging
70
+ hookstride projects update PROJECT_UUID --name "Production EU"
71
+
72
+ hookstride destinations list
73
+ hookstride destinations create --name "Webhook receiver" --url "https://app.example.com/webhooks/hookstride"
74
+ hookstride destinations update DESTINATION_UUID --url "https://api.example.com/webhooks/hookstride"
75
+ hookstride destinations update DESTINATION_UUID --pause
76
+ hookstride destinations update DESTINATION_UUID --resume
77
+ hookstride keys list
78
+ hookstride events list --status failed
79
+ hookstride events show EVENT_UUID
80
+ hookstride events send DESTINATION_UUID --type webhook.test --wait
81
+ hookstride stats
82
+
83
+ hookstride incoming sources
84
+ hookstride incoming routes
85
+ hookstride incoming bindings
86
+ hookstride incoming registration-keys
87
+
88
+ hookstride billing status
89
+ hookstride billing history
90
+ hookstride config show
91
+ ```
92
+
93
+ Replace the example UUIDs with identifiers from your account. Find your workspace's `account_id` with `hookstride --json projects list`; that ID is required for project creation. Project creation and renaming require an admin/owner role. Destination changes require developer access or higher.
94
+
95
+ Commands that operate on a project use the selected project. You can override the selection for an individual command:
96
+
97
+ ```bash
98
+ hookstride --project PROJECT_UUID events list
99
+ ```
100
+
101
+ ### Interactive console
102
+
103
+ ```bash
104
+ hookstride console
105
+ ```
106
+
107
+ Use `help` to view commands, Tab for completion, and `exit` or Ctrl+D to leave. The console also supports `show projects`, `show events`, `show destinations`, `use PROJECT_UUID`, `back`, and `set env dev|production`. The same `projects create/update`, `destinations create/update`, and `events send` commands work inside the console. Commands with customer-provided names and URLs are not saved to console history.
108
+
109
+ ### JSON output
110
+
111
+ Use `--json` before a command to retrieve structured data for scripts:
112
+
113
+ ```bash
114
+ hookstride --json projects list
115
+ hookstride --project PROJECT_UUID --json events list --status failed
116
+ hookstride --env production --json billing history
117
+ ```
118
+
119
+ Errors go to standard error; unsuccessful requests return a nonzero exit code. When creating a destination, the server returns a signing secret **once**. Save it securely immediately. Both terminal output and `--json` deliberately include that one-time secret, so avoid piping creation output into logs or public CI artifacts.
120
+
121
+ ### Send a test event
122
+
123
+ Use an existing active destination from `hookstride destinations list`.
124
+ The command securely prompts for a project delivery API key (`whrk_`). It cannot use a
125
+ Control API token (`whrctl_`); these credentials have different permissions.
126
+
127
+ ```bash
128
+ hookstride --env production projects use PROJECT_UUID
129
+ hookstride --env production events send DESTINATION_UUID --wait
130
+ hookstride --env production events show EVENT_UUID
131
+ ```
132
+
133
+ The event type defaults to `webhook.test`, with a harmless JSON payload:
134
+ `{"message":"Hookstride CLI delivery test","source":"cli"}`.
135
+ To send a different JSON object without placing its contents in shell history:
136
+
137
+ ```bash
138
+ hookstride --env production events send DESTINATION_UUID --type demo.delivery --payload-file ./demo-payload.json --wait
139
+ ```
140
+
141
+ To avoid the hidden prompt, set `HOOKSTRIDE_PRODUCTION_API_KEY` or
142
+ `HOOKSTRIDE_DEV_API_KEY` for the matching environment only.
143
+ Never add keys to CLI arguments, commit them to Git, or paste them into a public CI log.
144
+ The CLI does not save delivery keys or their prompts in its configuration or history.
145
+ The `--wait` flag polls for a terminal status and exits nonzero if delivery fails.
146
+ A non-delivered event can be examined using `events show` with the usual Control token.
147
+
148
+ ## Environments and local settings
149
+
150
+ The CLI connects to the production API by default: `https://api.hookstride.com`.
151
+ A new release must be published to PyPI before existing installations receive this change.
152
+
153
+ To inspect the development API explicitly, select it:
154
+
155
+ ```bash
156
+ hookstride --env dev console
157
+ ```
158
+
159
+ Development requests use `https://api-dev.hookstride.com`. Use a Control API token issued for the selected environment. A custom HTTPS API origin can be supplied with `--api-url`.
160
+
161
+ Project selections are stored separately by environment in `~/.config/hookstride/settings.json`. This file contains project identifiers, **not authentication tokens**. Console tokens and command history remain in memory and are discarded at exit.
162
+
163
+ ## Documentation
164
+
165
+ Documentation: https://hookstride.com
@@ -0,0 +1,152 @@
1
+ # Hookstride CLI
2
+
3
+ Hookstride CLI lets you manage projects and webhook destinations, inspect delivery activity, and view billing records. It includes an interactive console with the same selected-project commands.
4
+
5
+ Version 0.3.1 adds signed test-event sending with an existing project's delivery API key, and optional delivery-status polling. Project and destination management remain available; billing and credential changes, delivery replay, and destructive operations remain unavailable.
6
+
7
+ ## Installation
8
+
9
+
10
+ Requires Python 3.11 or later.
11
+
12
+ ```bash
13
+ uv tool install hookstride-cli
14
+ ```
15
+
16
+ Alternatively, use `pipx install hookstride-cli`.
17
+
18
+ ```bash
19
+ hookstride --version
20
+ hookstride status
21
+ hookstride console
22
+ ```
23
+
24
+ Upgrade an existing installation with `uv tool upgrade hookstride-cli`.
25
+
26
+ ## Authentication
27
+
28
+ Authenticated commands require a **Control API token** (`whrctl_`), available from your Hookstride dashboard. Project delivery API keys (`whrk_`) do not grant CLI access.
29
+
30
+ In an interactive console, run `auth login` and enter the token at the hidden prompt:
31
+
32
+ ```bash
33
+ hookstride console
34
+ ```
35
+
36
+ For one-off commands, set `HOOKSTRIDE_CONTROL_TOKEN` in your shell without entering it on the command line:
37
+
38
+ ```bash
39
+ read -rs "HOOKSTRIDE_CONTROL_TOKEN?Control token: "
40
+ echo
41
+ export HOOKSTRIDE_CONTROL_TOKEN
42
+ hookstride auth status
43
+ ```
44
+
45
+ The `read` example above works in **zsh**. In Bash, use `read -rs -p "Control token: " HOOKSTRIDE_CONTROL_TOKEN` followed by `echo` and `export HOOKSTRIDE_CONTROL_TOKEN`.
46
+
47
+ Tokens entered through `auth login` are retained only for the interactive console session. The CLI does not write tokens to its settings file.
48
+
49
+ ## Commands
50
+
51
+ ```bash
52
+ hookstride status
53
+ hookstride auth status
54
+ hookstride projects list
55
+ hookstride projects use PROJECT_UUID
56
+ hookstride projects create --account ACCOUNT_UUID --name "Staging" --slug staging
57
+ hookstride projects update PROJECT_UUID --name "Production EU"
58
+
59
+ hookstride destinations list
60
+ hookstride destinations create --name "Webhook receiver" --url "https://app.example.com/webhooks/hookstride"
61
+ hookstride destinations update DESTINATION_UUID --url "https://api.example.com/webhooks/hookstride"
62
+ hookstride destinations update DESTINATION_UUID --pause
63
+ hookstride destinations update DESTINATION_UUID --resume
64
+ hookstride keys list
65
+ hookstride events list --status failed
66
+ hookstride events show EVENT_UUID
67
+ hookstride events send DESTINATION_UUID --type webhook.test --wait
68
+ hookstride stats
69
+
70
+ hookstride incoming sources
71
+ hookstride incoming routes
72
+ hookstride incoming bindings
73
+ hookstride incoming registration-keys
74
+
75
+ hookstride billing status
76
+ hookstride billing history
77
+ hookstride config show
78
+ ```
79
+
80
+ Replace the example UUIDs with identifiers from your account. Find your workspace's `account_id` with `hookstride --json projects list`; that ID is required for project creation. Project creation and renaming require an admin/owner role. Destination changes require developer access or higher.
81
+
82
+ Commands that operate on a project use the selected project. You can override the selection for an individual command:
83
+
84
+ ```bash
85
+ hookstride --project PROJECT_UUID events list
86
+ ```
87
+
88
+ ### Interactive console
89
+
90
+ ```bash
91
+ hookstride console
92
+ ```
93
+
94
+ Use `help` to view commands, Tab for completion, and `exit` or Ctrl+D to leave. The console also supports `show projects`, `show events`, `show destinations`, `use PROJECT_UUID`, `back`, and `set env dev|production`. The same `projects create/update`, `destinations create/update`, and `events send` commands work inside the console. Commands with customer-provided names and URLs are not saved to console history.
95
+
96
+ ### JSON output
97
+
98
+ Use `--json` before a command to retrieve structured data for scripts:
99
+
100
+ ```bash
101
+ hookstride --json projects list
102
+ hookstride --project PROJECT_UUID --json events list --status failed
103
+ hookstride --env production --json billing history
104
+ ```
105
+
106
+ Errors go to standard error; unsuccessful requests return a nonzero exit code. When creating a destination, the server returns a signing secret **once**. Save it securely immediately. Both terminal output and `--json` deliberately include that one-time secret, so avoid piping creation output into logs or public CI artifacts.
107
+
108
+ ### Send a test event
109
+
110
+ Use an existing active destination from `hookstride destinations list`.
111
+ The command securely prompts for a project delivery API key (`whrk_`). It cannot use a
112
+ Control API token (`whrctl_`); these credentials have different permissions.
113
+
114
+ ```bash
115
+ hookstride --env production projects use PROJECT_UUID
116
+ hookstride --env production events send DESTINATION_UUID --wait
117
+ hookstride --env production events show EVENT_UUID
118
+ ```
119
+
120
+ The event type defaults to `webhook.test`, with a harmless JSON payload:
121
+ `{"message":"Hookstride CLI delivery test","source":"cli"}`.
122
+ To send a different JSON object without placing its contents in shell history:
123
+
124
+ ```bash
125
+ hookstride --env production events send DESTINATION_UUID --type demo.delivery --payload-file ./demo-payload.json --wait
126
+ ```
127
+
128
+ To avoid the hidden prompt, set `HOOKSTRIDE_PRODUCTION_API_KEY` or
129
+ `HOOKSTRIDE_DEV_API_KEY` for the matching environment only.
130
+ Never add keys to CLI arguments, commit them to Git, or paste them into a public CI log.
131
+ The CLI does not save delivery keys or their prompts in its configuration or history.
132
+ The `--wait` flag polls for a terminal status and exits nonzero if delivery fails.
133
+ A non-delivered event can be examined using `events show` with the usual Control token.
134
+
135
+ ## Environments and local settings
136
+
137
+ The CLI connects to the production API by default: `https://api.hookstride.com`.
138
+ A new release must be published to PyPI before existing installations receive this change.
139
+
140
+ To inspect the development API explicitly, select it:
141
+
142
+ ```bash
143
+ hookstride --env dev console
144
+ ```
145
+
146
+ Development requests use `https://api-dev.hookstride.com`. Use a Control API token issued for the selected environment. A custom HTTPS API origin can be supplied with `--api-url`.
147
+
148
+ Project selections are stored separately by environment in `~/.config/hookstride/settings.json`. This file contains project identifiers, **not authentication tokens**. Console tokens and command history remain in memory and are discarded at exit.
149
+
150
+ ## Documentation
151
+
152
+ Documentation: https://hookstride.com
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hookstride-cli"
7
- version = "0.2.1"
8
- description = "Command-line access to Hookstride projects, webhook activity, and billing."
7
+ version = "0.3.1"
8
+ description = "Manage Hookstride projects and destinations, inspect webhook activity and billing."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
11
11
  license = { text = "Proprietary" }
@@ -1,3 +1,3 @@
1
1
  """Hookstride developer CLI."""
2
2
 
3
- __version__ = "0.2.1"
3
+ __version__ = "0.3.1"
@@ -1,8 +1,7 @@
1
- """Interactive, read-only Hookstride console.
1
+ """Interactive Hookstride console with allowlisted project and destination writes.
2
2
 
3
- The console intentionally does not execute shell commands. It uses the same
4
- project-scoped Control API commands as the CLI, keeps tokens only in memory,
5
- and stores no history on disk.
3
+ The console never executes shell commands, retains tokens only in memory,
4
+ and stores no command history on disk.
6
5
  """
7
6
 
8
7
  from __future__ import annotations
@@ -25,20 +24,20 @@ from typer.main import get_command
25
24
  from . import main as cli
26
25
 
27
26
  # Only these typed commands may execute through the console.
28
- # Future write actions must be explicitly reviewed, not implicitly unlocked.
29
- READ_COMMANDS: dict[str, set[str]] = {
27
+ # Write actions are intentionally allowlisted, never automatically unlocked.
28
+ ALLOWED_COMMANDS: dict[str, set[str]] = {
30
29
  "auth": {"status"},
31
- "projects": {"list", "use"},
32
- "destinations": {"list"},
30
+ "projects": {"list", "use", "create", "update"},
31
+ "destinations": {"list", "create", "update"},
33
32
  "keys": {"list"},
34
- "events": {"list", "show"},
33
+ "events": {"list", "show", "send"},
35
34
  "billing": {"status", "history"},
36
35
  "incoming": {"sources", "routes", "bindings", "registration-keys"},
37
36
  "config": {"show"},
38
37
  }
39
38
  ROOT_COMMANDS = {"status", "stats"}
40
39
 
41
- # Aliases that feel like a familiar operator console, but remain read-only.
40
+ # Aliases that feel like a familiar operator console.
42
41
  SHOW_TARGETS: dict[str, tuple[str, ...] | None] = {
43
42
  "options": None,
44
43
  "projects": ("projects", "list"),
@@ -70,8 +69,10 @@ SAFE_HISTORY_COMMANDS = frozenset(
70
69
  COMMAND_COMPLETIONS = sorted(
71
70
  {
72
71
  *SAFE_HISTORY_COMMANDS,
73
- "use ", "projects use ", "events show ", "events list --status ",
72
+ "use ", "projects use ", "events show ", "events send ", "events list --status ",
74
73
  "events list --origin ", "events list --page ", "set project ",
74
+ "projects create --name ", "projects update ",
75
+ "destinations create --name ", "destinations update ",
75
76
  "set env ", "json ", "show ", "auth ",
76
77
  }
77
78
  )
@@ -194,6 +195,8 @@ class HookstrideConsole:
194
195
  "[bold]help[/bold] Show console help\n"
195
196
  "[bold]show options[/bold] Display environment, project and authentication\n"
196
197
  "[bold]show projects[/bold] List accessible projects\n"
198
+ "[bold]projects create --name N --account UUID[/bold] Create a project\n"
199
+ "[bold]projects update UUID --name N[/bold] Rename a project\n"
197
200
  "[bold]use UUID[/bold] Select a project (also saves preference)\n"
198
201
  "[bold]back[/bold] Leave the active project context\n"
199
202
  "[bold]set env dev[/bold] Switch to development API\n"
@@ -202,9 +205,12 @@ class HookstrideConsole:
202
205
  "[bold]auth logout[/bold] Clear the current environment's session token\n"
203
206
  "[bold]auth status[/bold] Validate current token\n"
204
207
  "[bold]show destinations[/bold] Inspect outgoing webhooks\n"
208
+ "[bold]destinations create --name N --url HTTPS_URL[/bold] Add receiver\n"
209
+ "[bold]destinations update UUID --pause[/bold] Pause a receiver\n"
205
210
  "[bold]show events[/bold] View recent events\n"
206
211
  "[bold]events list --status failed[/bold] Filter delivery history\n"
207
212
  "[bold]events show UUID[/bold] Inspect a delivery and attempts\n"
213
+ "[bold]events send DEST_UUID --wait[/bold] Send one signed delivery test\n"
208
214
  "[bold]show billing[/bold] View plan and credits\n"
209
215
  "[bold]show payments[/bold] View payment history\n"
210
216
  "[bold]show sources[/bold] Inspect incoming sources\n"
@@ -223,7 +229,6 @@ class HookstrideConsole:
223
229
  ["API", self.session.origin],
224
230
  ["Project", project],
225
231
  ["Authenticated token", "configured" if self._current_token() else "missing"],
226
- ["Mode", "read-only"],
227
232
  ]
228
233
  cli._table(_FakeContext(self.session), "Session options", ["Setting", "Value"], rows)
229
234
 
@@ -294,7 +299,7 @@ class HookstrideConsole:
294
299
  self._write("[green]✓[/green] Signed out for this console environment.")
295
300
 
296
301
  def _execute_cli(self, args: list[str], *, json_output: bool = False) -> None:
297
- """Invoke existing read-only Click/Typer commands, never a shell."""
302
+ """Invoke explicitly allowed Click/Typer commands, never a shell."""
298
303
  if not _allowed_cli(args):
299
304
  raise cli.CLIError("Unknown or unavailable command. Type 'help'.")
300
305
  group = args[0]
@@ -303,6 +308,8 @@ class HookstrideConsole:
303
308
  raise cli.CLIError("No project selected. Run 'show projects' then 'use UUID'.")
304
309
  if _requires_token(group, action) and not self._current_token():
305
310
  raise cli.CLIError("No management token for this environment. Run 'auth login'.")
311
+ if args[:2] == ["events", "show"] and len(args) == 2:
312
+ raise cli.CLIError("Usage: events show EVENT_UUID.")
306
313
  options = ["--env", self.environment, "--api-url", self.session.origin]
307
314
  if self.project:
308
315
  options += ["--project", self.project]
@@ -316,11 +323,19 @@ class HookstrideConsole:
316
323
  standalone_mode=False,
317
324
  )
318
325
  except click.exceptions.Exit as exc:
319
- # 'status' already displayed a red Offline panel. Do not add an
320
- # unrelated error when returning to the interactive prompt.
326
+ # The nested CLI must never terminate the interactive console.
327
+ if exc.exit_code == 0:
328
+ return
329
+ # 'status' already displayed a red Offline panel.
321
330
  if group == "status" and not json_output and exc.exit_code == 1:
322
331
  return
323
332
  raise cli.CLIError("Invalid command arguments. Type 'help'.") from None
333
+ except SystemExit as exc:
334
+ # Some Typer/Click error paths raise SystemExit instead of Exit.
335
+ # Do not let them unwind run() and clear in-memory authentication.
336
+ if exc.code in (0, None):
337
+ return
338
+ raise cli.CLIError("Invalid command arguments. Type 'help'.") from None
324
339
  except (click.ClickException, click.Abort):
325
340
  # Click errors can quote user-provided arguments; don't echo them.
326
341
  raise cli.CLIError("Invalid command arguments. Type 'help'.") from None
@@ -382,7 +397,7 @@ class HookstrideConsole:
382
397
 
383
398
  def run(self) -> None:
384
399
  self._write(
385
- "\n[bold cyan]HOOKSTRIDE[/bold cyan] [dim]CONSOLE v0.2[/dim]\n"
400
+ f"\n[bold cyan]HOOKSTRIDE[/bold cyan] [dim]CONSOLE v{cli.VERSION}[/dim]\n"
386
401
  "[dim]Type 'help' for commands, 'auth login' for a token, "
387
402
  "or 'exit' to quit.[/dim]\n"
388
403
  )
@@ -431,8 +446,8 @@ def _allowed_cli(parts: list[str]) -> bool:
431
446
  return len(parts) == 1
432
447
  return (
433
448
  len(parts) >= 2
434
- and parts[0] in READ_COMMANDS
435
- and parts[1] in READ_COMMANDS[parts[0]]
449
+ and parts[0] in ALLOWED_COMMANDS
450
+ and parts[1] in ALLOWED_COMMANDS[parts[0]]
436
451
  )
437
452
 
438
453
 
@@ -443,7 +458,8 @@ def _requires_project(group: str, action: str | None) -> bool:
443
458
 
444
459
 
445
460
  def _requires_token(group: str, action: str | None) -> bool:
446
- return group != "status" and not (group == "config" and action == "show")
461
+ return (group != "status" and not (group == "config" and action == "show")
462
+ and not (group == "events" and action == "send"))
447
463
 
448
464
 
449
465
  def run_console(session: cli.Session) -> None: