insightfactory-cli 1.0.1.dev6__tar.gz → 1.0.1.dev9__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.
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/CLAUDE.md +1 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/PKG-INFO +7 -1
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/README.md +6 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/pyproject.toml +1 -1
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/api.py +22 -5
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_api.py +40 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.github/workflows/ci.yml +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.github/workflows/claude.yml +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.github/workflows/release.yml +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.gitignore +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.python-version +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/AGENTS.md +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/__init__.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/__main__.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/cache.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/cli.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/colour.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/__init__.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/config.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/login.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/logout.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/profiles.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/set_token.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/token.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/config.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/constants.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/http.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/main.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/oauth.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/runtime.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/__init__.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/cache_writer.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/conftest.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/helpers.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/servers.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_api_command.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_cache.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_cli.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_config.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_config_command.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_login.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_oauth.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_oauth_flow.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_profiles.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_programmatic_api.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_runtime.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_set_token.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_token.py +0 -0
- {insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: insightfactory-cli
|
|
3
|
-
Version: 1.0.1.
|
|
3
|
+
Version: 1.0.1.dev9
|
|
4
4
|
Summary: Profile-based authentication CLI for the InsightFactory Interfaces API
|
|
5
5
|
Project-URL: Homepage, https://github.com/insightfactory-ai/insightfactory-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/insightfactory-ai/insightfactory-cli
|
|
@@ -102,6 +102,12 @@ prefixes.
|
|
|
102
102
|
Override the config directory with `INSIGHTFACTORY_CONFIG_DIR` (useful in tests
|
|
103
103
|
and CI). The default is `~/.insightfactory`.
|
|
104
104
|
|
|
105
|
+
The request method goes in `-X`; `if-cli api` takes exactly one positional
|
|
106
|
+
argument and reads it as the path. A `curl`-shaped `if-cli api GET /api/schedules`
|
|
107
|
+
therefore parses `GET` as the path — write `if-cli api -X GET /api/schedules`
|
|
108
|
+
instead. The CLI names the misplaced verb rather than reporting a problem with
|
|
109
|
+
`/api/schedules`.
|
|
110
|
+
|
|
105
111
|
On Git Bash (MSYS2) on Windows, path conversion rewrites a leading-slash
|
|
106
112
|
argument such as `/api/agent-projects` into a Windows path. Prefix the command
|
|
107
113
|
with `MSYS_NO_PATHCONV=1`:
|
|
@@ -86,6 +86,12 @@ prefixes.
|
|
|
86
86
|
Override the config directory with `INSIGHTFACTORY_CONFIG_DIR` (useful in tests
|
|
87
87
|
and CI). The default is `~/.insightfactory`.
|
|
88
88
|
|
|
89
|
+
The request method goes in `-X`; `if-cli api` takes exactly one positional
|
|
90
|
+
argument and reads it as the path. A `curl`-shaped `if-cli api GET /api/schedules`
|
|
91
|
+
therefore parses `GET` as the path — write `if-cli api -X GET /api/schedules`
|
|
92
|
+
instead. The CLI names the misplaced verb rather than reporting a problem with
|
|
93
|
+
`/api/schedules`.
|
|
94
|
+
|
|
89
95
|
On Git Bash (MSYS2) on Windows, path conversion rewrites a leading-slash
|
|
90
96
|
argument such as `/api/agent-projects` into a Windows path. Prefix the command
|
|
91
97
|
with `MSYS_NO_PATHCONV=1`:
|
|
@@ -61,6 +61,27 @@ def describe_route(document: dict[str, Any], method: str, path: str) -> dict[str
|
|
|
61
61
|
return operation if isinstance(operation, dict) else None
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
def _is_absolute_http_url(api_path: str) -> bool:
|
|
65
|
+
parsed = parse_url(api_path)
|
|
66
|
+
return parsed.scheme in {"http", "https"} and bool(parsed.hostname)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _die_on_misplaced_http_method(api_path: str, positionals: list[str]) -> None:
|
|
70
|
+
"""Explain a `curl`-shaped `if-cli api GET /path`, where the verb is read as the path.
|
|
71
|
+
|
|
72
|
+
Recognition spans every verb a user might reach for, not just the ones -X accepts:
|
|
73
|
+
naming the misplaced verb is more useful than a path error even for TRACE, which
|
|
74
|
+
-X then rejects on its own terms.
|
|
75
|
+
"""
|
|
76
|
+
method = api_path.lower()
|
|
77
|
+
if method not in HTTP_METHODS:
|
|
78
|
+
return
|
|
79
|
+
targets = [value for value in positionals[1:] if value.startswith("/") or _is_absolute_http_url(value)]
|
|
80
|
+
target = targets[0] if targets else "/api/path"
|
|
81
|
+
suggestion = f"if-cli api -X {method.upper()} {target}"
|
|
82
|
+
die(f"'{api_path}' looks like an HTTP method, not a path — did you mean: {suggestion} ?")
|
|
83
|
+
|
|
84
|
+
|
|
64
85
|
def _die_on_msys_mangled_path(api_path: str) -> None:
|
|
65
86
|
if not WINDOWS_DRIVE_PATH.search(api_path):
|
|
66
87
|
return
|
|
@@ -73,11 +94,6 @@ def _die_on_msys_mangled_path(api_path: str) -> None:
|
|
|
73
94
|
)
|
|
74
95
|
|
|
75
96
|
|
|
76
|
-
def _is_absolute_http_url(api_path: str) -> bool:
|
|
77
|
-
parsed = parse_url(api_path)
|
|
78
|
-
return parsed.scheme in {"http", "https"} and bool(parsed.hostname)
|
|
79
|
-
|
|
80
|
-
|
|
81
97
|
def resolve_api_url(host: str, api_path: str) -> ParseResult:
|
|
82
98
|
if not api_path.startswith("/") and not _is_absolute_http_url(api_path):
|
|
83
99
|
_die_on_msys_mangled_path(api_path)
|
|
@@ -145,6 +161,7 @@ def api_command(argv: list[str]) -> None:
|
|
|
145
161
|
api_path = positionals[0] if positionals else None
|
|
146
162
|
if not api_path:
|
|
147
163
|
die(API_USAGE)
|
|
164
|
+
_die_on_misplaced_http_method(api_path, positionals)
|
|
148
165
|
|
|
149
166
|
if values["method"] is not None:
|
|
150
167
|
method = values["method"].upper()
|
|
@@ -37,6 +37,46 @@ def test_api_rejects_unsupported_request_methods_with_a_cli_error():
|
|
|
37
37
|
assert "unsupported request method 'TRACE'" in result.stderr
|
|
38
38
|
|
|
39
39
|
|
|
40
|
+
def test_api_names_a_misplaced_http_method_instead_of_blaming_the_path():
|
|
41
|
+
result = run_cli(["api", "GET", "/api/schedules"])
|
|
42
|
+
assert result.returncode == 1
|
|
43
|
+
assert "'GET' looks like an HTTP method, not a path" in result.stderr
|
|
44
|
+
assert "did you mean: if-cli api -X GET /api/schedules ?" in result.stderr
|
|
45
|
+
assert "API path must begin with" not in result.stderr
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_api_detects_a_misplaced_http_method_in_any_case_and_position():
|
|
49
|
+
lowercase = run_cli(["api", "put", "/api/orchestration/run"])
|
|
50
|
+
assert lowercase.returncode == 1
|
|
51
|
+
assert "'put' looks like an HTTP method, not a path" in lowercase.stderr
|
|
52
|
+
assert "did you mean: if-cli api -X PUT /api/orchestration/run ?" in lowercase.stderr
|
|
53
|
+
|
|
54
|
+
before_profile = run_cli(["api", "DELETE", "/api/schedules/1", "-p", "example-dev"])
|
|
55
|
+
assert before_profile.returncode == 1
|
|
56
|
+
assert "did you mean: if-cli api -X DELETE /api/schedules/1 ?" in before_profile.stderr
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_api_keeps_a_same_origin_absolute_url_in_the_correction():
|
|
60
|
+
result = run_cli(["api", "GET", "https://factory.example/api/schedules"])
|
|
61
|
+
assert result.returncode == 1
|
|
62
|
+
assert "did you mean: if-cli api -X GET https://factory.example/api/schedules ?" in result.stderr
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_api_names_a_misplaced_verb_that_x_would_not_accept():
|
|
66
|
+
result = run_cli(["api", "TRACE", "/api/schedules"])
|
|
67
|
+
assert result.returncode == 1
|
|
68
|
+
assert "'TRACE' looks like an HTTP method, not a path" in result.stderr
|
|
69
|
+
assert "did you mean: if-cli api -X TRACE /api/schedules ?" in result.stderr
|
|
70
|
+
assert "API path must begin with" not in result.stderr
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_api_suggests_a_placeholder_path_when_only_a_method_was_supplied():
|
|
74
|
+
result = run_cli(["api", "POST"])
|
|
75
|
+
assert result.returncode == 1
|
|
76
|
+
assert "'POST' looks like an HTTP method, not a path" in result.stderr
|
|
77
|
+
assert "did you mean: if-cli api -X POST /api/path ?" in result.stderr
|
|
78
|
+
|
|
79
|
+
|
|
40
80
|
def test_discovers_and_sorts_all_openapi_operations():
|
|
41
81
|
assert discover_routes(OPENAPI) == [
|
|
42
82
|
"DELETE /api/agent-projects/{id} Delete an agent project",
|
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.github/workflows/claude.yml
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/.github/workflows/release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/__init__.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/config.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/login.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/logout.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/profiles.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/set_token.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/src/if_cli/commands/token.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_config_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.0.1.dev6 → insightfactory_cli-1.0.1.dev9}/tests/test_programmatic_api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|