@josephyan/qingflow-cli 0.2.0-beta.73 → 0.2.0-beta.74
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.
- package/README.md +2 -2
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/qingflow_mcp/backend_client.py +102 -0
- package/src/qingflow_mcp/builder_facade/service.py +609 -5
- package/src/qingflow_mcp/cli/commands/builder.py +33 -1
- package/src/qingflow_mcp/cli/commands/repo.py +80 -0
- package/src/qingflow_mcp/cli/context.py +3 -0
- package/src/qingflow_mcp/config.py +147 -0
- package/src/qingflow_mcp/repository_store.py +71 -0
- package/src/qingflow_mcp/response_trim.py +4 -0
- package/src/qingflow_mcp/server_app_builder.py +26 -1
- package/src/qingflow_mcp/tools/ai_builder_tools.py +110 -0
- package/src/qingflow_mcp/tools/repository_dev_tools.py +533 -0
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-cli@0.2.0-beta.
|
|
6
|
+
npm install @josephyan/qingflow-cli@0.2.0-beta.74
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.
|
|
12
|
+
npx -y -p @josephyan/qingflow-cli@0.2.0-beta.74 qingflow
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@josephyan/qingflow-cli",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.74",
|
|
4
4
|
"description": "Human-friendly Qingflow command line interface for auth, record operations, import, tasks, and stable builder flows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/pyproject.toml
CHANGED
|
@@ -88,6 +88,30 @@ class BackendClient:
|
|
|
88
88
|
unwrap=unwrap,
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
+
def public_request_with_headers(
|
|
92
|
+
self,
|
|
93
|
+
method: str,
|
|
94
|
+
base_url: str,
|
|
95
|
+
path: str,
|
|
96
|
+
*,
|
|
97
|
+
params: JSONObject | None = None,
|
|
98
|
+
json_body: JSONValue = None,
|
|
99
|
+
unwrap: bool = True,
|
|
100
|
+
qf_version: str | None = None,
|
|
101
|
+
headers: dict[str, str] | None = None,
|
|
102
|
+
) -> BackendResponse:
|
|
103
|
+
request_headers = self._base_headers(None, None, qf_version=qf_version)
|
|
104
|
+
if headers:
|
|
105
|
+
request_headers.update({key: value for key, value in headers.items() if value is not None})
|
|
106
|
+
return self._request_with_meta(
|
|
107
|
+
method,
|
|
108
|
+
self._build_url(base_url, path),
|
|
109
|
+
params=params,
|
|
110
|
+
json_body=json_body,
|
|
111
|
+
headers=request_headers,
|
|
112
|
+
unwrap=unwrap,
|
|
113
|
+
)
|
|
114
|
+
|
|
91
115
|
def request(
|
|
92
116
|
self,
|
|
93
117
|
method: str,
|
|
@@ -131,6 +155,54 @@ class BackendClient:
|
|
|
131
155
|
unwrap=unwrap,
|
|
132
156
|
)
|
|
133
157
|
|
|
158
|
+
def stream_request(
|
|
159
|
+
self,
|
|
160
|
+
method: str,
|
|
161
|
+
context: BackendRequestContext,
|
|
162
|
+
path: str,
|
|
163
|
+
*,
|
|
164
|
+
params: JSONObject | None = None,
|
|
165
|
+
json_body: JSONValue = None,
|
|
166
|
+
headers: dict[str, str] | None = None,
|
|
167
|
+
) -> list[str]:
|
|
168
|
+
request_headers = self._base_headers(
|
|
169
|
+
context.token,
|
|
170
|
+
context.ws_id,
|
|
171
|
+
context.qf_request_id,
|
|
172
|
+
qf_version=context.qf_version,
|
|
173
|
+
)
|
|
174
|
+
if headers:
|
|
175
|
+
request_headers.update({key: value for key, value in headers.items() if value is not None})
|
|
176
|
+
return self._stream_lines(
|
|
177
|
+
method,
|
|
178
|
+
self._build_url(context.base_url, path),
|
|
179
|
+
params=params,
|
|
180
|
+
json_body=json_body,
|
|
181
|
+
headers=request_headers,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def public_stream_request(
|
|
185
|
+
self,
|
|
186
|
+
method: str,
|
|
187
|
+
base_url: str,
|
|
188
|
+
path: str,
|
|
189
|
+
*,
|
|
190
|
+
params: JSONObject | None = None,
|
|
191
|
+
json_body: JSONValue = None,
|
|
192
|
+
headers: dict[str, str] | None = None,
|
|
193
|
+
qf_version: str | None = None,
|
|
194
|
+
) -> list[str]:
|
|
195
|
+
request_headers = self._base_headers(None, None, qf_version=qf_version)
|
|
196
|
+
if headers:
|
|
197
|
+
request_headers.update({key: value for key, value in headers.items() if value is not None})
|
|
198
|
+
return self._stream_lines(
|
|
199
|
+
method,
|
|
200
|
+
self._build_url(base_url, path),
|
|
201
|
+
params=params,
|
|
202
|
+
json_body=json_body,
|
|
203
|
+
headers=request_headers,
|
|
204
|
+
)
|
|
205
|
+
|
|
134
206
|
def describe_route(self, context: BackendRequestContext) -> JSONObject:
|
|
135
207
|
qf_version, source = self._resolve_qf_version(context.qf_version)
|
|
136
208
|
if context.qf_version is not None and context.qf_version_source:
|
|
@@ -430,6 +502,36 @@ class BackendClient:
|
|
|
430
502
|
assert last_error is not None
|
|
431
503
|
raise last_error
|
|
432
504
|
|
|
505
|
+
def _stream_lines(
|
|
506
|
+
self,
|
|
507
|
+
method: str,
|
|
508
|
+
url: str,
|
|
509
|
+
*,
|
|
510
|
+
params: JSONObject | None,
|
|
511
|
+
json_body: JSONValue,
|
|
512
|
+
headers: dict[str, str],
|
|
513
|
+
) -> list[str]:
|
|
514
|
+
try:
|
|
515
|
+
with self._client.stream(method.upper(), url, params=params, json=json_body, headers=headers) as response:
|
|
516
|
+
request_id = headers["Qf-Request-Id"]
|
|
517
|
+
if response.status_code >= 400:
|
|
518
|
+
raw_bytes = response.read()
|
|
519
|
+
payload: JSONValue
|
|
520
|
+
try:
|
|
521
|
+
payload = response.json()
|
|
522
|
+
except ValueError:
|
|
523
|
+
payload = raw_bytes.decode("utf-8", errors="replace")
|
|
524
|
+
raise QingflowApiError(
|
|
525
|
+
category="http",
|
|
526
|
+
message=self._extract_message(payload) or f"HTTP {response.status_code}",
|
|
527
|
+
backend_code=self._extract_code(payload),
|
|
528
|
+
request_id=request_id,
|
|
529
|
+
http_status=response.status_code,
|
|
530
|
+
)
|
|
531
|
+
return [line for line in response.iter_lines()]
|
|
532
|
+
except httpx.RequestError as exc:
|
|
533
|
+
raise QingflowApiError(category="network", message=str(exc), request_id=headers["Qf-Request-Id"])
|
|
534
|
+
|
|
433
535
|
def _parse_response(self, response: httpx.Response, request_id: str, *, unwrap: bool) -> JSONValue:
|
|
434
536
|
payload: JSONValue
|
|
435
537
|
try:
|