maxc-cli 0.1.5__tar.gz → 0.1.7__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.
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/PKG-INFO +4 -2
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/setup.py +4 -2
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/__init__.py +1 -1
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/query.py +8 -1
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/cli.py +5 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/exceptions.py +12 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/SKILL.md +2 -9
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/PKG-INFO +4 -2
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/MANIFEST.in +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/README.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/pyproject.toml +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/scripts/regression_test.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/setup.cfg +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/__main__.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/app.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/audit.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/auth_providers.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/__init__.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/auth.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/catalog.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/data.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/job.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/meta.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/backend/odps.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/cache.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/config.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/helpers.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/masking.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/models.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/output.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/setting_parser.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/agents/openai.yaml +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/nohup.out +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/bootstrap-auth.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/command-patterns.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/maxcompute-sql-notes.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/migrate-from-odpscmd.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/partition-guide.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/skills/references/setup-install.md +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/store.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli/utils.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/SOURCES.txt +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/dependency_links.txt +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/entry_points.txt +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/requires.txt +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/src/maxc_cli.egg-info/top_level.txt +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_agent_hints_and_cli.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_agent_skill_commands_context.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_cache.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_catalog.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_cli_mock.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_compat.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_e2e_smoke.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_error_self_correction.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_external_auth.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_integration.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_integration_real.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_job_improvements.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_masking.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_phase1_improvements.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_query_auto_promote.py +0 -0
- {maxc_cli-0.1.5 → maxc_cli-0.1.7}/tests/test_setting_parser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maxc-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Agent-native MaxCompute CLI for external coding agents
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.8
|
|
@@ -8,7 +8,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3.10
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
-
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Python: >=3.8
|
|
12
14
|
Description-Content-Type: text/markdown
|
|
13
15
|
Requires-Dist: PyYAML>=5.4
|
|
14
16
|
Requires-Dist: pyodps
|
|
@@ -9,11 +9,11 @@ README = ROOT / "README.md"
|
|
|
9
9
|
|
|
10
10
|
setup(
|
|
11
11
|
name="maxc-cli",
|
|
12
|
-
version="0.1.
|
|
12
|
+
version="0.1.7",
|
|
13
13
|
description="Agent-native MaxCompute CLI for external coding agents",
|
|
14
14
|
long_description=README.read_text(encoding="utf-8"),
|
|
15
15
|
long_description_content_type="text/markdown",
|
|
16
|
-
python_requires=">=3.8
|
|
16
|
+
python_requires=">=3.8",
|
|
17
17
|
package_dir={"": "src"},
|
|
18
18
|
packages=find_packages(where="src"),
|
|
19
19
|
include_package_data=True,
|
|
@@ -31,6 +31,8 @@ setup(
|
|
|
31
31
|
"Programming Language :: Python :: 3.10",
|
|
32
32
|
"Programming Language :: Python :: 3.11",
|
|
33
33
|
"Programming Language :: Python :: 3.12",
|
|
34
|
+
"Programming Language :: Python :: 3.13",
|
|
35
|
+
"Programming Language :: Python :: 3.14",
|
|
34
36
|
],
|
|
35
37
|
install_requires=[
|
|
36
38
|
"PyYAML>=5.4",
|
|
@@ -115,10 +115,17 @@ class QueryMixin:
|
|
|
115
115
|
instance = self.client.execute_sql(
|
|
116
116
|
actual_sql, project=project, hints=hints,
|
|
117
117
|
)
|
|
118
|
+
except Exception as exc:
|
|
119
|
+
raise translate_odps_error(exc) from exc
|
|
120
|
+
|
|
121
|
+
try:
|
|
118
122
|
# Default timeout: 300 seconds (5 minutes) to prevent indefinite blocking
|
|
119
123
|
instance.wait_for_success(timeout=timeout or 300)
|
|
120
124
|
except Exception as exc:
|
|
121
|
-
|
|
125
|
+
err = translate_odps_error(exc)
|
|
126
|
+
err.instance_id = instance.id
|
|
127
|
+
err.logview = self._safe_logview(instance)
|
|
128
|
+
raise err from exc
|
|
122
129
|
|
|
123
130
|
elapsed_ms = int((monotonic() - started_monotonic) * 1000)
|
|
124
131
|
result = self._instance_to_query_result(
|
|
@@ -512,6 +512,7 @@ def run(
|
|
|
512
512
|
"BACKEND_CONNECTION_ERROR": _AUTH_HINTS,
|
|
513
513
|
"PERMISSION_DENIED": AgentHints(
|
|
514
514
|
actions=[action("auth.can-i"), action("auth.whoami")],
|
|
515
|
+
insights=[f"Current project: {app.config.default_project}"] if app else [],
|
|
515
516
|
),
|
|
516
517
|
"NOT_FOUND": AgentHints(
|
|
517
518
|
actions=[action("meta.search"), action("meta.list-tables")],
|
|
@@ -572,6 +573,10 @@ def run(
|
|
|
572
573
|
emit_json(payload.to_dict(), stdout)
|
|
573
574
|
else:
|
|
574
575
|
stderr.write(render_error(exc.error_code, exc.message, exc.suggestion) + "\n")
|
|
576
|
+
if getattr(exc, "instance_id", None):
|
|
577
|
+
stderr.write(f" Instance ID: {exc.instance_id}\n")
|
|
578
|
+
if getattr(exc, "logview", None):
|
|
579
|
+
stderr.write(f" LogView: {exc.logview}\n")
|
|
575
580
|
return exc.exit_code
|
|
576
581
|
except Exception as exc:
|
|
577
582
|
error_payload = ErrorPayload(
|
|
@@ -10,6 +10,8 @@ class ErrorPayload:
|
|
|
10
10
|
suggestion: 'str | None'
|
|
11
11
|
recoverable: 'bool'
|
|
12
12
|
recovery_steps: 'list[str]' = field(default_factory=list)
|
|
13
|
+
instance_id: 'str | None' = None
|
|
14
|
+
logview: 'str | None' = None
|
|
13
15
|
|
|
14
16
|
def to_dict(self) -> 'dict[str, Any]':
|
|
15
17
|
payload: 'dict[str, Any]' = {
|
|
@@ -21,6 +23,10 @@ class ErrorPayload:
|
|
|
21
23
|
payload["suggestion"] = self.suggestion
|
|
22
24
|
if self.recovery_steps:
|
|
23
25
|
payload["recovery_steps"] = self.recovery_steps
|
|
26
|
+
if self.instance_id:
|
|
27
|
+
payload["instance_id"] = self.instance_id
|
|
28
|
+
if self.logview:
|
|
29
|
+
payload["logview"] = self.logview
|
|
24
30
|
return payload
|
|
25
31
|
|
|
26
32
|
|
|
@@ -35,10 +41,14 @@ class MaxCError(Exception):
|
|
|
35
41
|
*,
|
|
36
42
|
suggestion: 'str | None' = None,
|
|
37
43
|
recoverable: 'bool | None' = None,
|
|
44
|
+
instance_id: 'str | None' = None,
|
|
45
|
+
logview: 'str | None' = None,
|
|
38
46
|
) -> 'None':
|
|
39
47
|
super().__init__(message)
|
|
40
48
|
self.message = message
|
|
41
49
|
self.suggestion = suggestion
|
|
50
|
+
self.instance_id = instance_id
|
|
51
|
+
self.logview = logview
|
|
42
52
|
if recoverable is None:
|
|
43
53
|
self.recoverable = self.__class__.recoverable
|
|
44
54
|
else:
|
|
@@ -52,6 +62,8 @@ class MaxCError(Exception):
|
|
|
52
62
|
suggestion=self.suggestion,
|
|
53
63
|
recoverable=self.recoverable,
|
|
54
64
|
recovery_steps=steps,
|
|
65
|
+
instance_id=self.instance_id,
|
|
66
|
+
logview=self.logview,
|
|
55
67
|
)
|
|
56
68
|
|
|
57
69
|
def _default_recovery_steps(self) -> 'list[str]':
|
|
@@ -93,7 +93,6 @@ See [references/migrate-from-odpscmd.md](references/migrate-from-odpscmd.md) for
|
|
|
93
93
|
- Trust runtime help and actual command output over stale snippets.
|
|
94
94
|
- Never install or upgrade Python without explicit user confirmation.
|
|
95
95
|
- Prefer `auth login` over hand-editing `~/.maxc/config.yaml`.
|
|
96
|
-
- `meta list-tables` is cache-backed; falls back to live backend query on cache miss.
|
|
97
96
|
- `meta search` uses Catalog API (server-side FTS via pyodps RestClient) when auto-routed; falls back to cache-backed substring match, then live scan. No extra SDK dependency required.
|
|
98
97
|
- Most meta commands support `--schema` to override the session default (list-tables, search, search-columns).
|
|
99
98
|
- `session set/show/unset` are local-only — no authenticated backend required.
|
|
@@ -101,11 +100,9 @@ See [references/migrate-from-odpscmd.md](references/migrate-from-odpscmd.md) for
|
|
|
101
100
|
- `agent skill` returns the SKILL.md path and metadata.
|
|
102
101
|
- `agent install-skill <platform>` registers the skill with an Agent platform (claude-code, cursor, windsurf, codex, qwen, qoder, qoderwork). Idempotent; re-run after `pip install --upgrade` to update local skill files.
|
|
103
102
|
- Use normalized `data` shapes: `auth whoami` → `data.identity`, `query`/`job result` → `data.result`, `meta describe` → `data.table`, `data sample` → `data.sample`.
|
|
104
|
-
- Use `agent_hints.actions[]` for structured action
|
|
105
|
-
- Use `agent_hints.action_ids` for stable program logic; `next_actions` are hints only.
|
|
103
|
+
- Use `agent_hints.actions[]` for structured navigation. Each action has `id`, `title`, `command`. Use `actions[].id` for stable program logic. Do not execute `next_actions` strings directly — they may have broken shell quoting; construct commands yourself from the action `id` and context.
|
|
106
104
|
- Before exploring an unfamiliar project, ask the user which schema/table they need — do not iterate all schemas.
|
|
107
105
|
- When a query fails with `SQL_ERROR`, read `error.suggestion` before retrying. Do not retry the same SQL unchanged.
|
|
108
|
-
- `next_actions` commands may have broken shell quoting when SQL contains single quotes. Use `actions[].id` to identify the action, then construct the command yourself if needed.
|
|
109
106
|
- For partitioned tables, always determine the partition value via `meta latest-partition` or `meta partitions` before querying.
|
|
110
107
|
- When writing SQL for date-partitioned tables, use the exact partition format returned by `meta latest-partition` (format varies by table).
|
|
111
108
|
|
|
@@ -284,15 +281,12 @@ See [references/maxcompute-sql-notes.md](references/maxcompute-sql-notes.md) for
|
|
|
284
281
|
| Using `maxc sql ...` | The command is `maxc query ...` |
|
|
285
282
|
| Using `auth login --from-env` without checking env vars exist | Run `auth whoami --json` first; only use `--from-env` when env vars are confirmed set |
|
|
286
283
|
| Hand-editing `~/.maxc/config.yaml` | Use `auth login` |
|
|
287
|
-
| Calling `meta list-tables` on a cold cache | Tables are fetched live on cache miss; `cache build` improves speed for repeat queries |
|
|
288
284
|
| Inventing endpoints | Only use endpoints the user provided or that exist in current config |
|
|
289
285
|
| Using `job wait --stream` and expecting a JSON envelope | `--stream` emits NDJSON; use plain `job wait --json` for envelope |
|
|
290
286
|
| Running a query without checking cost first | Use `query cost` before large queries; use `--cost-check` to set auto-abort threshold |
|
|
291
287
|
| Ignoring `agent_hints.warnings` in the response | Always check warnings — they surface backend issues, cache staleness, and cost alerts |
|
|
292
288
|
| Assuming `meta describe` data is live | Cache source may be stale; check `metadata.source` field and `agent_hints.warnings` |
|
|
293
|
-
| Querying partitioned table without
|
|
294
|
-
| Using `MAX_PT()` in ad-hoc queries | Prefer literal values from `meta latest-partition`; MAX_PT may return incomplete partitions |
|
|
295
|
-
| Hardcoding partition dates like `ds = '20260101'` | Use `meta latest-partition` to get the actual latest value |
|
|
289
|
+
| Querying partitioned table without partition filter, or hardcoding/guessing partition values | Always run `meta latest-partition` first; use the exact returned value in WHERE (see Partition Query Strategy) |
|
|
296
290
|
| Assuming 2-tier naming (`project.table`) | Check if project uses 3-tier namespace with `meta list-schemas` |
|
|
297
291
|
|
|
298
292
|
## Agent Anti-Patterns
|
|
@@ -303,7 +297,6 @@ See [references/maxcompute-sql-notes.md](references/maxcompute-sql-notes.md) for
|
|
|
303
297
|
| Retrying the exact same failed SQL without changes | Same input → same error | Read `error.suggestion`, fix the SQL, then retry |
|
|
304
298
|
| Using `SELECT *` on unknown tables | May scan TB of data, hit cost limits | Use `meta describe` first, then select only needed columns with LIMIT |
|
|
305
299
|
| Generating SQL without checking column names first | Column names are often non-obvious (Chinese, abbreviated) | Always `meta describe` before writing SQL |
|
|
306
|
-
| Assuming partition format (e.g. `YYYY-MM-DD`) | Format varies by table (`20260415` vs `2026-04-15`) | Use `meta latest-partition` to get exact format |
|
|
307
300
|
| Running multiple queries when one suffices | Wastes compute and time | Combine into a single query with JOINs or subqueries |
|
|
308
301
|
|
|
309
302
|
## Error Recovery
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: maxc-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Agent-native MaxCompute CLI for external coding agents
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.8
|
|
@@ -8,7 +8,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
8
8
|
Classifier: Programming Language :: Python :: 3.10
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
-
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Python: >=3.8
|
|
12
14
|
Description-Content-Type: text/markdown
|
|
13
15
|
Requires-Dist: PyYAML>=5.4
|
|
14
16
|
Requires-Dist: pyodps
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|