licos-platform-cli 0.2.4__tar.gz → 0.2.6__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.
@@ -33,17 +33,16 @@ Thumbs.db
33
33
  *.log
34
34
  *.pid
35
35
  .licos
36
+ .tmp
36
37
 
37
38
  /tmp
38
-
39
- /Docs/hermes-agent
40
- /Docs/OpenCode
41
- /Docs/平台API
39
+ tools/android-sdk-cache/*.zip
42
40
 
43
41
  *.codex-*
44
42
 
45
43
  dist
44
+ logs
45
+
46
+ source
46
47
 
47
- project-20260423_130440
48
- projects-20260425_workflow
49
- coze-skills
48
+ 平台API
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: licos-platform-cli
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: LICOS platform CLI
5
5
  Requires-Python: >=3.10
6
- Requires-Dist: licos-platform-sdk>=0.2.3
6
+ Requires-Dist: licos-platform-sdk>=0.2.5
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-platform-cli"
7
- version = "0.2.4"
8
- description = "LICOS platform CLI"
7
+ version = "0.2.6"
8
+ description = "LICOS platform CLI"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
11
- "licos-platform-sdk>=0.2.3",
11
+ "licos-platform-sdk>=0.2.5",
12
12
  ]
13
13
 
14
14
  [project.scripts]
@@ -1,248 +1,295 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import json
5
- from typing import Any, Callable
6
-
7
- from licos_platform_sdk import database
8
-
9
-
10
- Handler = Callable[[argparse.Namespace], Any]
11
-
12
-
13
- def _set_handler(parser: argparse.ArgumentParser, handler: Handler) -> None:
14
- parser.set_defaults(handler=handler)
15
-
16
-
17
- def _json_value(value: str) -> Any:
18
- try:
19
- return json.loads(value)
20
- except json.JSONDecodeError:
21
- return value
22
-
23
-
24
- def _json_object(value: str | None) -> dict[str, Any] | None:
25
- if not value:
26
- return None
27
- parsed = _json_value(value)
28
- if not isinstance(parsed, dict):
29
- raise argparse.ArgumentTypeError("value must be a JSON object")
30
- return parsed
31
-
32
-
33
- def _json_list(value: str | None) -> list[Any] | None:
34
- if not value:
35
- return None
36
- parsed = _json_value(value)
37
- if not isinstance(parsed, list):
38
- raise argparse.ArgumentTypeError("value must be a JSON array")
39
- return parsed
40
-
41
-
42
- def _filters(args: argparse.Namespace) -> list[dict[str, Any]] | None:
43
- raw_filters = getattr(args, "filter", None) or []
44
- filters = []
45
- for item in raw_filters:
46
- field, op, raw_value = item
47
- filters.append({"field": field, "op": op, "value": _json_value(raw_value)})
48
- return filters or None
49
-
50
-
51
- def _order_by(args: argparse.Namespace) -> list[dict[str, str]] | None:
52
- raw_orders = getattr(args, "order", None) or []
53
- orders = []
54
- for item in raw_orders:
55
- if ":" in item:
56
- field, direction = item.rsplit(":", 1)
57
- else:
58
- field, direction = item, "asc"
59
- orders.append({"field": field, "direction": direction})
60
- return orders or None
61
-
62
-
63
- def _range(args: argparse.Namespace) -> dict[str, int] | None:
64
- if not getattr(args, "range", None):
65
- return None
66
- start, end = args.range
67
- return {"from": start, "to": end}
68
-
69
-
70
- def _query_options(args: argparse.Namespace) -> dict[str, Any]:
71
- return {
72
- "select": args.select,
73
- "filters": _filters(args),
74
- "order_by": _order_by(args),
75
- "range": _range(args),
76
- "limit": args.limit,
77
- "offset": args.offset,
78
- "count": args.count,
79
- "head": args.head,
80
- }
81
-
82
-
83
- def _cmd_query(args: argparse.Namespace) -> Any:
84
- return database.query(args.table, **_query_options(args))
85
-
86
-
87
- def _cmd_single(args: argparse.Namespace) -> Any:
88
- return database.single(
89
- args.table,
90
- maybe=args.maybe,
91
- select=args.select,
92
- filters=_filters(args),
93
- order_by=_order_by(args),
94
- )
95
-
96
-
97
- def _cmd_aggregate(args: argparse.Namespace) -> Any:
98
- return database.aggregate(
99
- args.table,
100
- args.aggregate,
101
- field=args.field,
102
- group_by=args.group_by,
103
- filters=_filters(args),
104
- )
105
-
106
-
107
- def _cmd_insert(args: argparse.Namespace) -> Any:
108
- if not args.row and not args.rows:
109
- raise argparse.ArgumentTypeError("--row or --rows is required")
110
- return database.insert(
111
- args.table,
112
- row=_json_object(args.row),
113
- rows=_json_list(args.rows),
114
- returning=not args.no_returning,
115
- )
116
-
117
-
118
- def _cmd_update(args: argparse.Namespace) -> Any:
119
- if not args.values and not args.updates:
120
- raise argparse.ArgumentTypeError("--values or --updates is required")
121
- return database.update(
122
- args.table,
123
- values=_json_object(args.values),
124
- filters=_filters(args),
125
- updates=_json_list(args.updates),
126
- returning=not args.no_returning,
127
- )
128
-
129
-
130
- def _cmd_delete_rows(args: argparse.Namespace) -> Any:
131
- filters = _filters(args)
132
- if not filters and not args.deletes:
133
- raise argparse.ArgumentTypeError("--filter or --deletes is required")
134
- return database.delete(
135
- args.table,
136
- filters=filters,
137
- deletes=_json_list(args.deletes),
138
- returning=not args.no_returning,
139
- )
140
-
141
-
142
- def _cmd_upsert(args: argparse.Namespace) -> Any:
143
- if not args.row and not args.rows:
144
- raise argparse.ArgumentTypeError("--row or --rows is required")
145
- return database.upsert(
146
- args.table,
147
- row=_json_object(args.row),
148
- rows=_json_list(args.rows),
149
- conflict_keys=args.conflict_keys,
150
- returning=not args.no_returning,
151
- )
152
-
153
-
154
- def _cmd_transaction(args: argparse.Namespace) -> Any:
155
- operations = _json_list(args.operations)
156
- if operations is None:
157
- raise argparse.ArgumentTypeError("--operations is required")
158
- return database.transaction(operations)
159
-
160
-
161
- def _cmd_rpc(args: argparse.Namespace) -> Any:
162
- return database.rpc(args.function_name, args=_json_object(args.args) or {})
163
-
164
-
165
- def _add_filter_args(parser: argparse.ArgumentParser) -> None:
166
- parser.add_argument(
167
- "--filter",
168
- nargs=3,
169
- action="append",
170
- metavar=("FIELD", "OP", "VALUE"),
171
- help="Add a filter. VALUE is parsed as JSON when possible.",
172
- )
173
-
174
-
175
- def _add_query_args(parser: argparse.ArgumentParser) -> None:
176
- parser.add_argument("--select", default=None, help="Comma-separated fields")
177
- _add_filter_args(parser)
178
- parser.add_argument("--order", action="append", default=[], help="Order by field or field:desc")
179
- parser.add_argument("--range", nargs=2, type=int, metavar=("FROM", "TO"))
180
- parser.add_argument("--limit", type=int, default=None)
181
- parser.add_argument("--offset", type=int, default=None)
182
- parser.add_argument("--count", action="store_true")
183
- parser.add_argument("--head", action="store_true")
184
-
185
-
186
- def add_database_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
187
- database_parser = subparsers.add_parser("database", help="Call LICOS runtime database APIs")
188
- database_subparsers = database_parser.add_subparsers(dest="database_command", required=True)
189
-
190
- query = database_subparsers.add_parser("query", help="Query rows")
191
- query.add_argument("table")
192
- _add_query_args(query)
193
- _set_handler(query, _cmd_query)
194
-
195
- single = database_subparsers.add_parser("single", help="Query a single row")
196
- single.add_argument("table")
197
- single.add_argument("--maybe", action="store_true", help="Allow zero rows")
198
- single.add_argument("--select", default=None, help="Comma-separated fields")
199
- _add_filter_args(single)
200
- single.add_argument("--order", action="append", default=[], help="Order by field or field:desc")
201
- _set_handler(single, _cmd_single)
202
-
203
- aggregate = database_subparsers.add_parser("aggregate", help="Run aggregate query")
204
- aggregate.add_argument("table")
205
- aggregate.add_argument("aggregate")
206
- aggregate.add_argument("--field", default=None)
207
- aggregate.add_argument("--group-by", action="append", default=None)
208
- _add_filter_args(aggregate)
209
- _set_handler(aggregate, _cmd_aggregate)
210
-
211
- insert = database_subparsers.add_parser("insert", help="Insert row(s)")
212
- insert.add_argument("table")
213
- insert.add_argument("--row", default=None, help="JSON object")
214
- insert.add_argument("--rows", default=None, help="JSON array")
215
- insert.add_argument("--no-returning", action="store_true")
216
- _set_handler(insert, _cmd_insert)
217
-
218
- update = database_subparsers.add_parser("update", help="Update row(s)")
219
- update.add_argument("table")
220
- update.add_argument("--values", default=None, help="JSON object")
221
- update.add_argument("--updates", default=None, help="JSON array of mutation batches")
222
- update.add_argument("--no-returning", action="store_true")
223
- _add_filter_args(update)
224
- _set_handler(update, _cmd_update)
225
-
226
- delete_rows = database_subparsers.add_parser("delete-rows", help="Delete row(s)")
227
- delete_rows.add_argument("table")
228
- delete_rows.add_argument("--deletes", default=None, help="JSON array of mutation batches")
229
- delete_rows.add_argument("--no-returning", action="store_true")
230
- _add_filter_args(delete_rows)
231
- _set_handler(delete_rows, _cmd_delete_rows)
232
-
233
- upsert = database_subparsers.add_parser("upsert", help="Upsert row(s)")
234
- upsert.add_argument("table")
235
- upsert.add_argument("--row", default=None, help="JSON object")
236
- upsert.add_argument("--rows", default=None, help="JSON array")
237
- upsert.add_argument("--conflict-keys", action="append", default=None)
238
- upsert.add_argument("--no-returning", action="store_true")
239
- _set_handler(upsert, _cmd_upsert)
240
-
241
- transaction = database_subparsers.add_parser("transaction", help="Run transaction")
242
- transaction.add_argument("--operations", required=True, help="JSON array")
243
- _set_handler(transaction, _cmd_transaction)
244
-
245
- rpc = database_subparsers.add_parser("rpc", help="Call database function")
246
- rpc.add_argument("function_name")
247
- rpc.add_argument("--args", default=None, help="JSON object")
248
- _set_handler(rpc, _cmd_rpc)
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any, Callable
8
+
9
+ from licos_platform_sdk import database
10
+
11
+
12
+ Handler = Callable[[argparse.Namespace], Any]
13
+
14
+
15
+ def _set_handler(parser: argparse.ArgumentParser, handler: Handler) -> None:
16
+ parser.set_defaults(handler=handler)
17
+
18
+
19
+ def _json_value(value: str) -> Any:
20
+ try:
21
+ return json.loads(value)
22
+ except json.JSONDecodeError:
23
+ return value
24
+
25
+
26
+ def _json_object(value: str | None) -> dict[str, Any] | None:
27
+ if not value:
28
+ return None
29
+ parsed = _json_value(value)
30
+ if not isinstance(parsed, dict):
31
+ raise argparse.ArgumentTypeError("value must be a JSON object")
32
+ return parsed
33
+
34
+
35
+ def _json_list(value: str | None) -> list[Any] | None:
36
+ if not value:
37
+ return None
38
+ parsed = _json_value(value)
39
+ if not isinstance(parsed, list):
40
+ raise argparse.ArgumentTypeError("value must be a JSON array")
41
+ return parsed
42
+
43
+
44
+ def _filters(args: argparse.Namespace) -> list[dict[str, Any]] | None:
45
+ raw_filters = getattr(args, "filter", None) or []
46
+ filters = []
47
+ for item in raw_filters:
48
+ field, op, raw_value = item
49
+ filters.append({"field": field, "op": op, "value": _json_value(raw_value)})
50
+ return filters or None
51
+
52
+
53
+ def _order_by(args: argparse.Namespace) -> list[dict[str, str]] | None:
54
+ raw_orders = getattr(args, "order", None) or []
55
+ orders = []
56
+ for item in raw_orders:
57
+ if ":" in item:
58
+ field, direction = item.rsplit(":", 1)
59
+ else:
60
+ field, direction = item, "asc"
61
+ orders.append({"field": field, "direction": direction})
62
+ return orders or None
63
+
64
+
65
+ def _range(args: argparse.Namespace) -> dict[str, int] | None:
66
+ if not getattr(args, "range", None):
67
+ return None
68
+ start, end = args.range
69
+ return {"from": start, "to": end}
70
+
71
+
72
+ def _query_options(args: argparse.Namespace) -> dict[str, Any]:
73
+ return {
74
+ "select": args.select,
75
+ "filters": _filters(args),
76
+ "order_by": _order_by(args),
77
+ "range": _range(args),
78
+ "limit": args.limit,
79
+ "offset": args.offset,
80
+ "count": args.count,
81
+ "head": args.head,
82
+ }
83
+
84
+
85
+ def _cmd_query(args: argparse.Namespace) -> Any:
86
+ return database.query(args.table, **_query_options(args))
87
+
88
+
89
+ def _cmd_single(args: argparse.Namespace) -> Any:
90
+ return database.single(
91
+ args.table,
92
+ maybe=args.maybe,
93
+ select=args.select,
94
+ filters=_filters(args),
95
+ order_by=_order_by(args),
96
+ )
97
+
98
+
99
+ def _cmd_aggregate(args: argparse.Namespace) -> Any:
100
+ return database.aggregate(
101
+ args.table,
102
+ args.aggregate,
103
+ field=args.field,
104
+ group_by=args.group_by,
105
+ filters=_filters(args),
106
+ )
107
+
108
+
109
+ def _cmd_insert(args: argparse.Namespace) -> Any:
110
+ if not args.row and not args.rows:
111
+ raise argparse.ArgumentTypeError("--row or --rows is required")
112
+ return database.insert(
113
+ args.table,
114
+ row=_json_object(args.row),
115
+ rows=_json_list(args.rows),
116
+ returning=not args.no_returning,
117
+ )
118
+
119
+
120
+ def _cmd_update(args: argparse.Namespace) -> Any:
121
+ if not args.values and not args.updates:
122
+ raise argparse.ArgumentTypeError("--values or --updates is required")
123
+ return database.update(
124
+ args.table,
125
+ values=_json_object(args.values),
126
+ filters=_filters(args),
127
+ updates=_json_list(args.updates),
128
+ returning=not args.no_returning,
129
+ )
130
+
131
+
132
+ def _cmd_delete_rows(args: argparse.Namespace) -> Any:
133
+ filters = _filters(args)
134
+ if not filters and not args.deletes:
135
+ raise argparse.ArgumentTypeError("--filter or --deletes is required")
136
+ return database.delete(
137
+ args.table,
138
+ filters=filters,
139
+ deletes=_json_list(args.deletes),
140
+ returning=not args.no_returning,
141
+ )
142
+
143
+
144
+ def _cmd_upsert(args: argparse.Namespace) -> Any:
145
+ if not args.row and not args.rows:
146
+ raise argparse.ArgumentTypeError("--row or --rows is required")
147
+ return database.upsert(
148
+ args.table,
149
+ row=_json_object(args.row),
150
+ rows=_json_list(args.rows),
151
+ conflict_keys=args.conflict_keys,
152
+ returning=not args.no_returning,
153
+ )
154
+
155
+
156
+ def _cmd_transaction(args: argparse.Namespace) -> Any:
157
+ operations = _json_list(args.operations)
158
+ if operations is None:
159
+ raise argparse.ArgumentTypeError("--operations is required")
160
+ return database.transaction(operations)
161
+
162
+
163
+ def _cmd_rpc(args: argparse.Namespace) -> Any:
164
+ return database.rpc(args.function_name, args=_json_object(args.args) or {})
165
+
166
+
167
+ def _cmd_schema(args: argparse.Namespace) -> Any:
168
+ return database.get_schema()
169
+
170
+
171
+ def _cmd_export_orm(args: argparse.Namespace) -> Any:
172
+ try:
173
+ content = database.export_orm(language=args.language, orm=args.orm)
174
+ resolved_orm = args.orm or database.default_orm(args.language)
175
+ except ValueError as exc:
176
+ raise argparse.ArgumentTypeError(str(exc)) from exc
177
+
178
+ output_path = _resolve_project_output(args.out)
179
+ output_path.parent.mkdir(parents=True, exist_ok=True)
180
+ output_path.write_text(content, encoding="utf-8")
181
+ return {
182
+ "language": args.language,
183
+ "orm": resolved_orm,
184
+ "path": str(output_path),
185
+ "bytes": len(content.encode("utf-8")),
186
+ }
187
+
188
+
189
+ def _resolve_project_output(value: str) -> Path:
190
+ output_path = Path(value)
191
+ project_root = os.environ.get("LICOS_PROJECT_PATH")
192
+ if not project_root:
193
+ return output_path
194
+ root = Path(project_root).resolve()
195
+ resolved = (output_path if output_path.is_absolute() else Path.cwd() / output_path).resolve()
196
+ try:
197
+ resolved.relative_to(root)
198
+ except ValueError as exc:
199
+ raise argparse.ArgumentTypeError("--out must stay inside LICOS_PROJECT_PATH") from exc
200
+ return resolved
201
+
202
+
203
+ def _add_filter_args(parser: argparse.ArgumentParser) -> None:
204
+ parser.add_argument(
205
+ "--filter",
206
+ nargs=3,
207
+ action="append",
208
+ metavar=("FIELD", "OP", "VALUE"),
209
+ help="Add a filter. VALUE is parsed as JSON when possible.",
210
+ )
211
+
212
+
213
+ def _add_query_args(parser: argparse.ArgumentParser) -> None:
214
+ parser.add_argument("--select", default=None, help="Comma-separated fields")
215
+ _add_filter_args(parser)
216
+ parser.add_argument("--order", action="append", default=[], help="Order by field or field:desc")
217
+ parser.add_argument("--range", nargs=2, type=int, metavar=("FROM", "TO"))
218
+ parser.add_argument("--limit", type=int, default=None)
219
+ parser.add_argument("--offset", type=int, default=None)
220
+ parser.add_argument("--count", action="store_true")
221
+ parser.add_argument("--head", action="store_true")
222
+
223
+
224
+ def add_database_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
225
+ database_parser = subparsers.add_parser("database", help="Call LICOS runtime database APIs")
226
+ database_subparsers = database_parser.add_subparsers(dest="database_command", required=True)
227
+
228
+ query = database_subparsers.add_parser("query", help="Query rows")
229
+ query.add_argument("table")
230
+ _add_query_args(query)
231
+ _set_handler(query, _cmd_query)
232
+
233
+ single = database_subparsers.add_parser("single", help="Query a single row")
234
+ single.add_argument("table")
235
+ single.add_argument("--maybe", action="store_true", help="Allow zero rows")
236
+ single.add_argument("--select", default=None, help="Comma-separated fields")
237
+ _add_filter_args(single)
238
+ single.add_argument("--order", action="append", default=[], help="Order by field or field:desc")
239
+ _set_handler(single, _cmd_single)
240
+
241
+ aggregate = database_subparsers.add_parser("aggregate", help="Run aggregate query")
242
+ aggregate.add_argument("table")
243
+ aggregate.add_argument("aggregate")
244
+ aggregate.add_argument("--field", default=None)
245
+ aggregate.add_argument("--group-by", action="append", default=None)
246
+ _add_filter_args(aggregate)
247
+ _set_handler(aggregate, _cmd_aggregate)
248
+
249
+ insert = database_subparsers.add_parser("insert", help="Insert row(s)")
250
+ insert.add_argument("table")
251
+ insert.add_argument("--row", default=None, help="JSON object")
252
+ insert.add_argument("--rows", default=None, help="JSON array")
253
+ insert.add_argument("--no-returning", action="store_true")
254
+ _set_handler(insert, _cmd_insert)
255
+
256
+ update = database_subparsers.add_parser("update", help="Update row(s)")
257
+ update.add_argument("table")
258
+ update.add_argument("--values", default=None, help="JSON object")
259
+ update.add_argument("--updates", default=None, help="JSON array of mutation batches")
260
+ update.add_argument("--no-returning", action="store_true")
261
+ _add_filter_args(update)
262
+ _set_handler(update, _cmd_update)
263
+
264
+ delete_rows = database_subparsers.add_parser("delete-rows", help="Delete row(s)")
265
+ delete_rows.add_argument("table")
266
+ delete_rows.add_argument("--deletes", default=None, help="JSON array of mutation batches")
267
+ delete_rows.add_argument("--no-returning", action="store_true")
268
+ _add_filter_args(delete_rows)
269
+ _set_handler(delete_rows, _cmd_delete_rows)
270
+
271
+ upsert = database_subparsers.add_parser("upsert", help="Upsert row(s)")
272
+ upsert.add_argument("table")
273
+ upsert.add_argument("--row", default=None, help="JSON object")
274
+ upsert.add_argument("--rows", default=None, help="JSON array")
275
+ upsert.add_argument("--conflict-keys", action="append", default=None)
276
+ upsert.add_argument("--no-returning", action="store_true")
277
+ _set_handler(upsert, _cmd_upsert)
278
+
279
+ transaction = database_subparsers.add_parser("transaction", help="Run transaction")
280
+ transaction.add_argument("--operations", required=True, help="JSON array")
281
+ _set_handler(transaction, _cmd_transaction)
282
+
283
+ rpc = database_subparsers.add_parser("rpc", help="Call database function")
284
+ rpc.add_argument("function_name")
285
+ rpc.add_argument("--args", default=None, help="JSON object")
286
+ _set_handler(rpc, _cmd_rpc)
287
+
288
+ schema = database_subparsers.add_parser("schema", help="Fetch database schema metadata")
289
+ _set_handler(schema, _cmd_schema)
290
+
291
+ export_orm = database_subparsers.add_parser("export-orm", help="Export ORM source from database schema metadata")
292
+ export_orm.add_argument("--language", required=True, choices=["typescript", "python"])
293
+ export_orm.add_argument("--orm", choices=["drizzle", "sqlalchemy"], default=None)
294
+ export_orm.add_argument("--out", required=True, help="Output source file path")
295
+ _set_handler(export_orm, _cmd_export_orm)