insightfactory-cli 1.1.2.dev30__tar.gz → 1.1.2.dev31__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.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/CHANGELOG.md +6 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/PKG-INFO +9 -1
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/README.md +8 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/pyproject.toml +1 -1
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/mcp.py +4 -1
- insightfactory_cli-1.1.2.dev31/src/if_cli/router/log.py +20 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/server.py +24 -1
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_mcp_command.py +6 -6
- insightfactory_cli-1.1.2.dev31/tests/test_router_log.py +23 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_upstream.py +4 -1
- insightfactory_cli-1.1.2.dev30/src/if_cli/router/log.py +0 -13
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.github/workflows/ci.yml +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.github/workflows/claude.yml +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.github/workflows/release.yml +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.gitignore +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.python-version +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/AGENTS.md +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/CLAUDE.md +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/LICENSE +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/__init__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/__main__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/assets/__init__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/assets/insightfactoryai-logo.svg +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/cache.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/callback_page.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/cli.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/colour.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/__init__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/api.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/config.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/login.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/logout.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/profiles.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/set_token.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/token.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/config.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/constants.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/http.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/main.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/oauth.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/__init__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/catalog.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/content.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/policy.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/upstream.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/runtime.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/__init__.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/cache_writer.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/conftest.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/helpers.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/servers.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_api.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_api_command.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_cache.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_cli.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_config.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_config_command.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_login.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_oauth.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_oauth_flow.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_oauth_force_refresh.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_profiles.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_programmatic_api.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_release_tools.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_catalog.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_content.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_policy.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_resources.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_server.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_runtime.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_set_token.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_token.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tools/check_release.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tools/release_notes.py +0 -0
- {insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/uv.lock +0 -0
|
@@ -31,6 +31,12 @@ last one has been released, so a cycle's PRs share a section.
|
|
|
31
31
|
|
|
32
32
|
### Changed
|
|
33
33
|
|
|
34
|
+
- The router's stderr lines now carry the elapsed time since startup, and it logs when
|
|
35
|
+
the catalogue build starts and when it answers its first `initialize`, so an operator
|
|
36
|
+
can tell a slow process apart from a slow factory and a client that called before the
|
|
37
|
+
handshake finished. `if-cli mcp` also now logs a `starting on Python <version>` line
|
|
38
|
+
before doing anything else, so a process that dies during argument parsing, config
|
|
39
|
+
load, or profile lookup still leaves one line on stderr instead of none.
|
|
34
40
|
- `release-guard` asks every PR into `develop` for a `CHANGELOG.md` entry, and asks
|
|
35
41
|
for a version bump only when `develop` is still on the version `main` is on. One
|
|
36
42
|
bump opens a release cycle and the PRs after it add to the section it opened,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: insightfactory-cli
|
|
3
|
-
Version: 1.1.2.
|
|
3
|
+
Version: 1.1.2.dev31
|
|
4
4
|
Summary: Profile-based authentication CLI for the InsightFactory Interfaces API
|
|
5
5
|
Project-URL: Homepage, https://insightfactory.ai
|
|
6
6
|
Author-email: "insightfactory.ai Support" <support@insightfactory.ai>
|
|
@@ -265,6 +265,14 @@ uv tool install 'insightfactory-cli[mcp]'
|
|
|
265
265
|
uvx --from 'insightfactory-cli[mcp]' if-cli mcp foundry
|
|
266
266
|
```
|
|
267
267
|
|
|
268
|
+
The first `uvx` launch resolves and downloads the package from PyPI before it runs, which
|
|
269
|
+
added roughly four to six seconds on top of the usual startup in local testing, against
|
|
270
|
+
under two seconds once `uv`'s cache was warm. A client with a fixed handshake budget
|
|
271
|
+
(Claude Code allows 30 seconds) usually has room for that, but a slow network can close
|
|
272
|
+
the gap. Two ways to avoid paying it on every launch: `uv tool install 'insightfactory-cli[mcp]'`
|
|
273
|
+
puts a real script on `PATH` with no resolve step, or run the same `uvx --from ...` command
|
|
274
|
+
by hand once before pointing a client at it, which warms `uv`'s cache for the launches after.
|
|
275
|
+
|
|
268
276
|
Add it to `.mcp.json`:
|
|
269
277
|
|
|
270
278
|
```json
|
|
@@ -241,6 +241,14 @@ uv tool install 'insightfactory-cli[mcp]'
|
|
|
241
241
|
uvx --from 'insightfactory-cli[mcp]' if-cli mcp foundry
|
|
242
242
|
```
|
|
243
243
|
|
|
244
|
+
The first `uvx` launch resolves and downloads the package from PyPI before it runs, which
|
|
245
|
+
added roughly four to six seconds on top of the usual startup in local testing, against
|
|
246
|
+
under two seconds once `uv`'s cache was warm. A client with a fixed handshake budget
|
|
247
|
+
(Claude Code allows 30 seconds) usually has room for that, but a slow network can close
|
|
248
|
+
the gap. Two ways to avoid paying it on every launch: `uv tool install 'insightfactory-cli[mcp]'`
|
|
249
|
+
puts a real script on `PATH` with no resolve step, or run the same `uvx --from ...` command
|
|
250
|
+
by hand once before pointing a client at it, which warms `uv`'s cache for the launches after.
|
|
251
|
+
|
|
244
252
|
Add it to `.mcp.json`:
|
|
245
253
|
|
|
246
254
|
```json
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/mcp.py
RENAMED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import importlib.util
|
|
4
|
+
import platform
|
|
4
5
|
import sys
|
|
5
6
|
|
|
6
7
|
from if_cli.cli import Options, parse_args
|
|
7
8
|
from if_cli.config import config_file, get_profile, list_factories, load_config, parse_factory_section
|
|
8
9
|
from if_cli.http import parse_timeout_seconds
|
|
10
|
+
from if_cli.router.log import log
|
|
9
11
|
from if_cli.runtime import die
|
|
10
12
|
|
|
11
13
|
MCP_OPTIONS: Options = {
|
|
@@ -75,6 +77,8 @@ def _stray_positional(rest: list[str]) -> str | None:
|
|
|
75
77
|
|
|
76
78
|
|
|
77
79
|
def mcp_command(argv: list[str]) -> None:
|
|
80
|
+
log(f"starting on Python {platform.python_version()}")
|
|
81
|
+
|
|
78
82
|
if "-h" in argv or "--help" in argv:
|
|
79
83
|
sys.stdout.write(MCP_USAGE)
|
|
80
84
|
return
|
|
@@ -146,7 +150,6 @@ def mcp_command(argv: list[str]) -> None:
|
|
|
146
150
|
# import bug inside if_cli.router propagates instead of reading as a missing extra.
|
|
147
151
|
if importlib.util.find_spec("mcp") is None:
|
|
148
152
|
die(MISSING_MCP_EXTRA)
|
|
149
|
-
from if_cli.router.log import log
|
|
150
153
|
from if_cli.router.server import build_router, run_server
|
|
151
154
|
|
|
152
155
|
timeout = parse_timeout_seconds(values["timeout"], "--timeout")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
# Captured at import: this module loads before the router does anything else
|
|
7
|
+
# diagnosable, so it stands in for process start. Two `log()` lines can then
|
|
8
|
+
# be subtracted to time the phase between them.
|
|
9
|
+
_START = time.monotonic()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def log(message: str) -> None:
|
|
13
|
+
"""Write one timestamped diagnostic line to stderr.
|
|
14
|
+
|
|
15
|
+
The router speaks MCP over stdout, so stderr is the only channel that can
|
|
16
|
+
carry anything to the operator. This lives in its own module because both
|
|
17
|
+
`server` and `upstream` write to it and `server` imports `upstream`.
|
|
18
|
+
"""
|
|
19
|
+
elapsed_ms = round((time.monotonic() - _START) * 1000)
|
|
20
|
+
sys.stderr.write(f"[if-cli mcp] +{elapsed_ms}ms {message}\n")
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/server.py
RENAMED
|
@@ -9,7 +9,7 @@ from typing import Any, TypeVar
|
|
|
9
9
|
import anyio
|
|
10
10
|
import mcp_types as types
|
|
11
11
|
from mcp.server import Server
|
|
12
|
-
from mcp.server.context import ServerRequestContext
|
|
12
|
+
from mcp.server.context import CallNext, HandlerResult, ServerMiddleware, ServerRequestContext
|
|
13
13
|
from mcp.server.stdio import stdio_server
|
|
14
14
|
from mcp.shared.exceptions import MCPError
|
|
15
15
|
|
|
@@ -137,6 +137,7 @@ class Router:
|
|
|
137
137
|
|
|
138
138
|
async def build_catalog(self) -> list[types.Tool]:
|
|
139
139
|
"""Build the merged catalogue. Safe to call again to pick up a new login."""
|
|
140
|
+
log(f"catalogue: building from {self.config.catalog_source}")
|
|
140
141
|
catalogues = await self._catalogues()
|
|
141
142
|
source = catalogues.get(self.config.catalog_source)
|
|
142
143
|
if source is None:
|
|
@@ -536,6 +537,27 @@ def advertised_extensions(router: Router) -> dict[str, dict[str, Any]]:
|
|
|
536
537
|
return {SKILLS_EXTENSION: {}} if router.config.skills else {}
|
|
537
538
|
|
|
538
539
|
|
|
540
|
+
def _log_first_initialize() -> ServerMiddleware[Any]:
|
|
541
|
+
"""Log once the router has answered a client's `initialize`.
|
|
542
|
+
|
|
543
|
+
Read against `prime_catalog`'s startup log lines, this tells an operator
|
|
544
|
+
apart a slow process (nothing logged yet), a slow factory (catalogue
|
|
545
|
+
build still running past this point), and a client that called before
|
|
546
|
+
the handshake (a tool call logged before this line ever appears).
|
|
547
|
+
"""
|
|
548
|
+
logged = False
|
|
549
|
+
|
|
550
|
+
async def middleware(ctx: ServerRequestContext[Any, Any], call_next: CallNext) -> HandlerResult:
|
|
551
|
+
nonlocal logged
|
|
552
|
+
result = await call_next(ctx)
|
|
553
|
+
if not logged and ctx.method == "initialize":
|
|
554
|
+
logged = True
|
|
555
|
+
log("answered the first initialize")
|
|
556
|
+
return result
|
|
557
|
+
|
|
558
|
+
return middleware
|
|
559
|
+
|
|
560
|
+
|
|
539
561
|
async def _serve(router: Router) -> None:
|
|
540
562
|
server: Server[Any] = Server(
|
|
541
563
|
SERVER_NAME,
|
|
@@ -553,6 +575,7 @@ async def _serve(router: Router) -> None:
|
|
|
553
575
|
# the handshake rebuilds its capabilities from `server.extensions` once the
|
|
554
576
|
# protocol version is known, and ignores the ones computed here.
|
|
555
577
|
server.extensions = advertised_extensions(router)
|
|
578
|
+
server.middleware.append(_log_first_initialize())
|
|
556
579
|
# Answer `initialize` immediately: the catalogue build runs as a background
|
|
557
580
|
# task so one hung factory reads as a slow tools/list, not a failed
|
|
558
581
|
# handshake (clients cap startup time).
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import os
|
|
5
|
+
import re
|
|
5
6
|
import subprocess
|
|
6
7
|
import sys
|
|
7
8
|
import time
|
|
@@ -802,11 +803,10 @@ def test_mcp_command_logs_the_resolved_factory_mapping_at_startup(tmp_path: Path
|
|
|
802
803
|
|
|
803
804
|
anyio.run(scenario)
|
|
804
805
|
stderr_text = stderr_path.read_text(encoding="utf-8")
|
|
805
|
-
expected = (
|
|
806
|
-
f"
|
|
807
|
-
f"tst=profile-b {server_b.origin}; catalog=dev"
|
|
806
|
+
expected = re.escape(
|
|
807
|
+
f"foundry: dev=profile-a {server_a.origin} (writable); tst=profile-b {server_b.origin}; catalog=dev"
|
|
808
808
|
)
|
|
809
|
-
assert expected
|
|
809
|
+
assert re.search(rf"\[if-cli mcp\] \+\d+ms {expected}", stderr_text)
|
|
810
810
|
finally:
|
|
811
811
|
server_a.close()
|
|
812
812
|
server_b.close()
|
|
@@ -827,8 +827,8 @@ def test_mcp_command_logs_environments_label_without_a_factory(tmp_path: Path):
|
|
|
827
827
|
|
|
828
828
|
anyio.run(scenario)
|
|
829
829
|
stderr_text = stderr_path.read_text(encoding="utf-8")
|
|
830
|
-
expected = f"
|
|
831
|
-
assert expected
|
|
830
|
+
expected = re.escape(f"environments: a=profile-a {server.origin} (writable); catalog=a")
|
|
831
|
+
assert re.search(rf"\[if-cli mcp\] \+\d+ms {expected}", stderr_text)
|
|
832
832
|
finally:
|
|
833
833
|
server.close()
|
|
834
834
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from if_cli.router import log as log_module
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_log_prefixes_the_elapsed_time_since_process_start(monkeypatch, capsys):
|
|
7
|
+
monkeypatch.setattr(log_module, "_START", 10.0)
|
|
8
|
+
monkeypatch.setattr(log_module.time, "monotonic", lambda: 10.25)
|
|
9
|
+
|
|
10
|
+
log_module.log("ready over stdio")
|
|
11
|
+
|
|
12
|
+
assert capsys.readouterr().err == "[if-cli mcp] +250ms ready over stdio\n"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_log_keeps_the_grep_prefix_first(monkeypatch, capsys):
|
|
16
|
+
"""`[if-cli mcp]` must stay the first thing on the line, timestamp or not:
|
|
17
|
+
it is what an operator (or a script) greps a stdio transcript for."""
|
|
18
|
+
monkeypatch.setattr(log_module, "_START", 0.0)
|
|
19
|
+
monkeypatch.setattr(log_module.time, "monotonic", lambda: 0.0)
|
|
20
|
+
|
|
21
|
+
log_module.log("WARN dropped a connect URL")
|
|
22
|
+
|
|
23
|
+
assert capsys.readouterr().err.startswith("[if-cli mcp] +0ms ")
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_upstream.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
+
import re
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
@@ -373,7 +374,9 @@ def test_a_dropped_connect_url_is_reported_on_stderr(capsys):
|
|
|
373
374
|
anyio.run(lambda: upstream.call_tool("run_sql_query", {}))
|
|
374
375
|
|
|
375
376
|
stderr = capsys.readouterr().err
|
|
376
|
-
assert
|
|
377
|
+
assert re.search(
|
|
378
|
+
r"\[if-cli mcp\] \+\d+ms WARN dropped a connect URL that is not on https://factory\.example", stderr
|
|
379
|
+
)
|
|
377
380
|
assert "https://phish.example/connect" in stderr
|
|
378
381
|
|
|
379
382
|
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def log(message: str) -> None:
|
|
7
|
-
"""Write one diagnostic line to stderr.
|
|
8
|
-
|
|
9
|
-
The router speaks MCP over stdout, so stderr is the only channel that can
|
|
10
|
-
carry anything to the operator. This lives in its own module because both
|
|
11
|
-
`server` and `upstream` write to it and `server` imports `upstream`.
|
|
12
|
-
"""
|
|
13
|
-
sys.stderr.write(f"[if-cli mcp] {message}\n")
|
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.github/workflows/claude.yml
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/.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
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/assets/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/callback_page.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/__init__.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/api.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/config.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/login.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/logout.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/profiles.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/commands/set_token.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/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
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/__init__.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/catalog.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/content.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/policy.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/src/if_cli/router/upstream.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
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_config_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_oauth_force_refresh.py
RENAMED
|
File without changes
|
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_programmatic_api.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_release_tools.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_catalog.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_content.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_policy.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_resources.py
RENAMED
|
File without changes
|
{insightfactory_cli-1.1.2.dev30 → insightfactory_cli-1.1.2.dev31}/tests/test_router_server.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|