hap-cli 0.5.0__py3-none-any.whl

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.
Files changed (58) hide show
  1. hap_cli/README.md +194 -0
  2. hap_cli/README_CN.md +601 -0
  3. hap_cli/__init__.py +3 -0
  4. hap_cli/commands/__init__.py +1 -0
  5. hap_cli/commands/ai_cmd.py +224 -0
  6. hap_cli/commands/app_cmd.py +308 -0
  7. hap_cli/commands/calendar_cmd.py +138 -0
  8. hap_cli/commands/chat_cmd.py +101 -0
  9. hap_cli/commands/config_cmd.py +169 -0
  10. hap_cli/commands/contact_cmd.py +125 -0
  11. hap_cli/commands/department_cmd.py +168 -0
  12. hap_cli/commands/group_cmd.py +128 -0
  13. hap_cli/commands/instance_cmd.py +310 -0
  14. hap_cli/commands/node_cmd.py +538 -0
  15. hap_cli/commands/optionset_cmd.py +99 -0
  16. hap_cli/commands/page_cmd.py +102 -0
  17. hap_cli/commands/plugin_cmd.py +133 -0
  18. hap_cli/commands/post_cmd.py +155 -0
  19. hap_cli/commands/record_cmd.py +228 -0
  20. hap_cli/commands/role_cmd.py +221 -0
  21. hap_cli/commands/workflow_cmd.py +284 -0
  22. hap_cli/commands/worksheet_cmd.py +342 -0
  23. hap_cli/context.py +43 -0
  24. hap_cli/core/__init__.py +1 -0
  25. hap_cli/core/ai.py +133 -0
  26. hap_cli/core/app.py +307 -0
  27. hap_cli/core/auth.py +219 -0
  28. hap_cli/core/calendar_mod.py +114 -0
  29. hap_cli/core/chat.py +73 -0
  30. hap_cli/core/contact.py +85 -0
  31. hap_cli/core/department.py +131 -0
  32. hap_cli/core/flow_node.py +1001 -0
  33. hap_cli/core/group.py +99 -0
  34. hap_cli/core/instance.py +572 -0
  35. hap_cli/core/optionset.py +112 -0
  36. hap_cli/core/page.py +138 -0
  37. hap_cli/core/plugin.py +87 -0
  38. hap_cli/core/post.py +118 -0
  39. hap_cli/core/record.py +268 -0
  40. hap_cli/core/role.py +227 -0
  41. hap_cli/core/session.py +348 -0
  42. hap_cli/core/workflow.py +556 -0
  43. hap_cli/core/worksheet.py +403 -0
  44. hap_cli/hap_cli.py +105 -0
  45. hap_cli/skills/SKILL.md +383 -0
  46. hap_cli/skills/__init__.py +0 -0
  47. hap_cli/tests/__init__.py +1 -0
  48. hap_cli/tests/test_core.py +1824 -0
  49. hap_cli/tests/test_full_e2e.py +136 -0
  50. hap_cli/tests/test_integration.py +805 -0
  51. hap_cli/utils/__init__.py +1 -0
  52. hap_cli/utils/formatting.py +111 -0
  53. hap_cli/utils/options.py +10 -0
  54. hap_cli-0.5.0.dist-info/METADATA +223 -0
  55. hap_cli-0.5.0.dist-info/RECORD +58 -0
  56. hap_cli-0.5.0.dist-info/WHEEL +5 -0
  57. hap_cli-0.5.0.dist-info/entry_points.txt +2 -0
  58. hap_cli-0.5.0.dist-info/top_level.txt +1 -0
hap_cli/core/group.py ADDED
@@ -0,0 +1,99 @@
1
+ """Group management for MingDAO HAP."""
2
+
3
+ from typing import Any, Optional
4
+
5
+ from hap_cli.core.session import Session
6
+
7
+
8
+ def get_groups(
9
+ session: Session,
10
+ project_id: str,
11
+ page_index: int = 1,
12
+ page_size: int = 50,
13
+ ) -> dict[str, Any]:
14
+ """Get group list."""
15
+ return session.api_call(
16
+ "Group", "GetGroups",
17
+ {"projectId": project_id, "pageIndex": page_index, "pageSize": page_size},
18
+ )
19
+
20
+
21
+ def get_group_info(
22
+ session: Session,
23
+ group_id: str,
24
+ ) -> dict[str, Any]:
25
+ """Get group information."""
26
+ return session.api_call("Group", "GetGroupInfo", {"groupId": group_id})
27
+
28
+
29
+ def add_group(
30
+ session: Session,
31
+ project_id: str,
32
+ group_name: str,
33
+ about: str = "",
34
+ member_ids: Optional[list[str]] = None,
35
+ ) -> dict[str, Any]:
36
+ """Create a new group."""
37
+ data: dict[str, Any] = {"projectId": project_id, "groupName": group_name}
38
+ if about:
39
+ data["about"] = about
40
+ if member_ids:
41
+ data["memberIds"] = member_ids
42
+ return session.api_call("Group", "AddGroup", data)
43
+
44
+
45
+ def remove_group(
46
+ session: Session,
47
+ group_id: str,
48
+ ) -> dict[str, Any]:
49
+ """Delete/disband a group."""
50
+ return session.api_call("Group", "RemoveGroup", {"groupId": group_id})
51
+
52
+
53
+ def get_group_users(
54
+ session: Session,
55
+ group_id: str,
56
+ page_index: int = 1,
57
+ page_size: int = 50,
58
+ ) -> dict[str, Any]:
59
+ """Get members of a group."""
60
+ return session.api_call(
61
+ "Group", "GetGroupUsers",
62
+ {"groupId": group_id, "pageIndex": page_index, "pageSize": page_size},
63
+ )
64
+
65
+
66
+ def remove_user(
67
+ session: Session,
68
+ group_id: str,
69
+ account_id: str,
70
+ ) -> dict[str, Any]:
71
+ """Remove a user from a group."""
72
+ return session.api_call(
73
+ "Group", "RemoveUser",
74
+ {"groupId": group_id, "accountId": account_id},
75
+ )
76
+
77
+
78
+ def update_group_name(
79
+ session: Session,
80
+ group_id: str,
81
+ group_name: str,
82
+ ) -> dict[str, Any]:
83
+ """Update group name."""
84
+ return session.api_call(
85
+ "Group", "UpdateGroupName",
86
+ {"groupId": group_id, "groupName": group_name},
87
+ )
88
+
89
+
90
+ def update_group_about(
91
+ session: Session,
92
+ group_id: str,
93
+ about: str,
94
+ ) -> dict[str, Any]:
95
+ """Update group about/announcement."""
96
+ return session.api_call(
97
+ "Group", "UpdateGroupAbout",
98
+ {"groupId": group_id, "about": about},
99
+ )
@@ -0,0 +1,572 @@
1
+ """Workflow instance and approval management for MingDAO HAP.
2
+
3
+ Covers: todo lists, instance details, approval operations (pass/reject/forward/sign),
4
+ execution history, batch operations, and instance lifecycle.
5
+ """
6
+
7
+ from typing import Any, Optional
8
+
9
+ from hap_cli.core.session import Session
10
+
11
+
12
+ # ── Instance Query ───────────────────────────────────────────────────────
13
+
14
+
15
+ def get_todo_count(session: Session) -> dict[str, Any]:
16
+ """Get count of pending workflow tasks.
17
+
18
+ Returns:
19
+ Counts by type (pending approval, pending fill, pending view)
20
+ """
21
+ return session.workflow_call("v1/instance/getTodoCount", {})
22
+
23
+
24
+ def get_todo_list(
25
+ session: Session,
26
+ page_index: int = 1,
27
+ page_size: int = 50,
28
+ type_: int = -1,
29
+ status: int = 0,
30
+ keyword: str = "",
31
+ process_id: str = "",
32
+ start_app_id: str = "",
33
+ start_date: str = "",
34
+ end_date: str = "",
35
+ apk_id: str = "",
36
+ ) -> dict[str, Any]:
37
+ """Get pending task list.
38
+
39
+ Args:
40
+ session: Active session
41
+ page_index: Page number
42
+ page_size: Items per page
43
+ type_: Task type (-1=all pending, 0=initiated, 3=fill, 4=approval, 5=view)
44
+ status: Status filter
45
+ keyword: Search keyword
46
+ process_id: Filter by process
47
+ start_app_id: Filter by source app
48
+ start_date: Start date filter (YYYY-MM-DD)
49
+ end_date: End date filter (YYYY-MM-DD)
50
+ apk_id: Filter by app
51
+
52
+ Returns:
53
+ Dict with task list and count
54
+ """
55
+ data: dict[str, Any] = {
56
+ "pageIndex": page_index,
57
+ "pageSize": page_size,
58
+ "type": type_,
59
+ }
60
+ if status:
61
+ data["status"] = status
62
+ if keyword:
63
+ data["keyword"] = keyword
64
+ if process_id:
65
+ data["processId"] = process_id
66
+ if start_app_id:
67
+ data["startAppId"] = start_app_id
68
+ if start_date:
69
+ data["startDate"] = start_date
70
+ if end_date:
71
+ data["endDate"] = end_date
72
+ if apk_id:
73
+ data["apkId"] = apk_id
74
+ result = session.workflow_call("v1/instance/getTodoList", data)
75
+ if isinstance(result, dict):
76
+ return {
77
+ "data": result.get("data", result.get("list", [])),
78
+ "count": result.get("count", result.get("total", 0)),
79
+ }
80
+ return {"data": result, "count": len(result)}
81
+
82
+
83
+ def get_instance(session: Session, instance_id: str) -> dict[str, Any]:
84
+ """Get instance basic info.
85
+
86
+ Args:
87
+ session: Active session
88
+ instance_id: Instance ID
89
+
90
+ Returns:
91
+ Instance detail
92
+ """
93
+ return session.workflow_call(
94
+ "instance/getInstance", {"instanceId": instance_id}
95
+ )
96
+
97
+
98
+ def get_instance_detail(
99
+ session: Session,
100
+ instance_id: str,
101
+ work_id: str = "",
102
+ ) -> dict[str, Any]:
103
+ """Get instance flow detail (v2).
104
+
105
+ Args:
106
+ session: Active session
107
+ instance_id: Instance ID
108
+ work_id: Work item ID
109
+
110
+ Returns:
111
+ Instance flow detail with node statuses
112
+ """
113
+ data: dict[str, Any] = {"id": instance_id}
114
+ if work_id:
115
+ data["workId"] = work_id
116
+ return session.workflow_call("v2/instance/get", data)
117
+
118
+
119
+ def get_operation_detail(
120
+ session: Session,
121
+ instance_id: str,
122
+ work_id: str = "",
123
+ ) -> dict[str, Any]:
124
+ """Get available operations for a task.
125
+
126
+ Args:
127
+ session: Active session
128
+ instance_id: Instance ID
129
+ work_id: Work item ID
130
+
131
+ Returns:
132
+ Operation options (approve, reject, etc.)
133
+ """
134
+ data: dict[str, Any] = {"id": instance_id}
135
+ if work_id:
136
+ data["workId"] = work_id
137
+ return session.workflow_call("instance/getOperationDetail", data)
138
+
139
+
140
+ def get_operation_history(
141
+ session: Session,
142
+ instance_id: str,
143
+ ) -> list[dict[str, Any]]:
144
+ """Get operation history of an instance.
145
+
146
+ Args:
147
+ session: Active session
148
+ instance_id: Instance ID
149
+
150
+ Returns:
151
+ List of operation records
152
+ """
153
+ result = session.workflow_call(
154
+ "instance/getOperationHistoryList",
155
+ {"instanceId": instance_id},
156
+ )
157
+ return result if isinstance(result, list) else result.get("list", [])
158
+
159
+
160
+ # ── Approval Operations ─────────────────────────────────────────────────
161
+
162
+
163
+ def _build_action_data(
164
+ instance_id: str,
165
+ work_id: str = "",
166
+ opinion: str = "",
167
+ back_node_id: str = "",
168
+ form_data: Optional[dict] = None,
169
+ signature: Optional[dict] = None,
170
+ ) -> dict[str, Any]:
171
+ """Build common approval action parameters."""
172
+ data: dict[str, Any] = {"id": instance_id}
173
+ if work_id:
174
+ data["workId"] = work_id
175
+ if opinion:
176
+ data["opinion"] = opinion
177
+ if back_node_id:
178
+ data["backNodeId"] = back_node_id
179
+ if form_data:
180
+ data["formData"] = form_data
181
+ if signature:
182
+ data["signature"] = signature
183
+ return data
184
+
185
+
186
+ def approve(
187
+ session: Session,
188
+ instance_id: str,
189
+ work_id: str = "",
190
+ opinion: str = "",
191
+ form_data: Optional[dict] = None,
192
+ signature: Optional[dict] = None,
193
+ ) -> dict[str, Any]:
194
+ """Approve/pass a workflow task.
195
+
196
+ Args:
197
+ session: Active session
198
+ instance_id: Instance ID
199
+ work_id: Work item ID
200
+ opinion: Approval comment
201
+ form_data: Form data updates
202
+ signature: Signature data
203
+
204
+ Returns:
205
+ Approval result
206
+ """
207
+ data = _build_action_data(instance_id, work_id, opinion, form_data=form_data, signature=signature)
208
+ return session.workflow_call("instance/pass", data)
209
+
210
+
211
+ def reject(
212
+ session: Session,
213
+ instance_id: str,
214
+ work_id: str = "",
215
+ opinion: str = "",
216
+ back_node_id: str = "",
217
+ form_data: Optional[dict] = None,
218
+ signature: Optional[dict] = None,
219
+ ) -> dict[str, Any]:
220
+ """Reject/overrule a workflow task.
221
+
222
+ Args:
223
+ session: Active session
224
+ instance_id: Instance ID
225
+ work_id: Work item ID
226
+ opinion: Rejection reason
227
+ back_node_id: Node ID to return to (for resubmission)
228
+ form_data: Form data updates
229
+ signature: Signature data
230
+
231
+ Returns:
232
+ Rejection result
233
+ """
234
+ data = _build_action_data(instance_id, work_id, opinion, back_node_id, form_data, signature)
235
+ return session.workflow_call("instance/overrule", data)
236
+
237
+
238
+ def forward(
239
+ session: Session,
240
+ instance_id: str,
241
+ forward_account_id: str,
242
+ work_id: str = "",
243
+ opinion: str = "",
244
+ ) -> dict[str, Any]:
245
+ """Forward/transfer a task to another user.
246
+
247
+ Args:
248
+ session: Active session
249
+ instance_id: Instance ID
250
+ forward_account_id: Target user account ID
251
+ work_id: Work item ID
252
+ opinion: Forward comment
253
+
254
+ Returns:
255
+ Forward result
256
+ """
257
+ data = _build_action_data(instance_id, work_id, opinion)
258
+ data["forwardAccountId"] = forward_account_id
259
+ return session.workflow_call("instance/forward", data)
260
+
261
+
262
+ def sign_task(
263
+ session: Session,
264
+ instance_id: str,
265
+ forward_account_id: str,
266
+ before: bool = True,
267
+ work_id: str = "",
268
+ opinion: str = "",
269
+ ) -> dict[str, Any]:
270
+ """Add a co-signer to a task.
271
+
272
+ Args:
273
+ session: Active session
274
+ instance_id: Instance ID
275
+ forward_account_id: Co-signer user ID
276
+ before: True=sign before current user, False=sign after
277
+ work_id: Work item ID
278
+ opinion: Comment
279
+
280
+ Returns:
281
+ Sign result
282
+ """
283
+ data = _build_action_data(instance_id, work_id, opinion)
284
+ data["forwardAccountId"] = forward_account_id
285
+ data["before"] = before
286
+ return session.workflow_call("instance/sign", data)
287
+
288
+
289
+ def submit(
290
+ session: Session,
291
+ instance_id: str,
292
+ work_id: str = "",
293
+ opinion: str = "",
294
+ form_data: Optional[dict] = None,
295
+ ) -> dict[str, Any]:
296
+ """Submit a fill-in task.
297
+
298
+ Args:
299
+ session: Active session
300
+ instance_id: Instance ID
301
+ work_id: Work item ID
302
+ opinion: Submit comment
303
+ form_data: Form data
304
+
305
+ Returns:
306
+ Submit result
307
+ """
308
+ data = _build_action_data(instance_id, work_id, opinion, form_data=form_data)
309
+ return session.workflow_call("instance/submit", data)
310
+
311
+
312
+ def revoke(
313
+ session: Session,
314
+ instance_id: str,
315
+ work_id: str = "",
316
+ ) -> dict[str, Any]:
317
+ """Revoke/withdraw a submitted instance (by initiator).
318
+
319
+ Args:
320
+ session: Active session
321
+ instance_id: Instance ID
322
+ work_id: Work item ID
323
+
324
+ Returns:
325
+ Revoke result
326
+ """
327
+ return session.workflow_call(
328
+ "instance/revoke",
329
+ _build_action_data(instance_id, work_id),
330
+ )
331
+
332
+
333
+ def task_revoke(
334
+ session: Session,
335
+ instance_id: str,
336
+ work_id: str = "",
337
+ ) -> dict[str, Any]:
338
+ """Revoke by approver (undo their own approval).
339
+
340
+ Args:
341
+ session: Active session
342
+ instance_id: Instance ID
343
+ work_id: Work item ID
344
+
345
+ Returns:
346
+ Revoke result
347
+ """
348
+ return session.workflow_call(
349
+ "instance/taskRevoke",
350
+ _build_action_data(instance_id, work_id),
351
+ )
352
+
353
+
354
+ def transfer(
355
+ session: Session,
356
+ instance_id: str,
357
+ forward_account_id: str,
358
+ work_id: str = "",
359
+ opinion: str = "",
360
+ ) -> dict[str, Any]:
361
+ """Transfer a fill-in task to another user.
362
+
363
+ Args:
364
+ session: Active session
365
+ instance_id: Instance ID
366
+ forward_account_id: Target user ID
367
+ work_id: Work item ID
368
+ opinion: Comment
369
+
370
+ Returns:
371
+ Transfer result
372
+ """
373
+ data = _build_action_data(instance_id, work_id, opinion)
374
+ data["forwardAccountId"] = forward_account_id
375
+ return session.workflow_call("instance/transfer", data)
376
+
377
+
378
+ def urge(
379
+ session: Session,
380
+ instance_id: str,
381
+ work_id: str = "",
382
+ ) -> dict[str, Any]:
383
+ """Send an urge/reminder for a pending task.
384
+
385
+ Args:
386
+ session: Active session
387
+ instance_id: Instance ID
388
+ work_id: Work item ID
389
+
390
+ Returns:
391
+ Urge result
392
+ """
393
+ data: dict[str, Any] = {"id": instance_id, "operationType": 18}
394
+ if work_id:
395
+ data["workId"] = work_id
396
+ return session.workflow_call("instance/operation", data)
397
+
398
+
399
+ # ── Batch Operations ────────────────────────────────────────────────────
400
+
401
+
402
+ def batch_operation(
403
+ session: Session,
404
+ batch_operation_type: int,
405
+ instance_id: str = "",
406
+ work_id: str = "",
407
+ page_index: int = 1,
408
+ page_size: int = 50,
409
+ type_: int = -1,
410
+ apk_id: str = "",
411
+ process_id: str = "",
412
+ selects: Optional[list] = None,
413
+ ) -> dict[str, Any]:
414
+ """Batch approve/reject/forward tasks.
415
+
416
+ Args:
417
+ session: Active session
418
+ batch_operation_type: 4=pass, 5=reject
419
+ instance_id: Instance ID (for single)
420
+ work_id: Work item ID
421
+ page_index: Page
422
+ page_size: Size
423
+ type_: Task type filter
424
+ apk_id: App filter
425
+ process_id: Process filter
426
+ selects: Selected item IDs for batch
427
+
428
+ Returns:
429
+ Batch result
430
+ """
431
+ data: dict[str, Any] = {
432
+ "batchOperationType": batch_operation_type,
433
+ "pageIndex": page_index,
434
+ "pageSize": page_size,
435
+ "type": type_,
436
+ }
437
+ if instance_id:
438
+ data["id"] = instance_id
439
+ if work_id:
440
+ data["workId"] = work_id
441
+ if apk_id:
442
+ data["apkId"] = apk_id
443
+ if process_id:
444
+ data["processId"] = process_id
445
+ if selects:
446
+ data["selects"] = selects
447
+ return session.workflow_call("v2/instance/batch", data)
448
+
449
+
450
+ # ── Execution History ────────────────────────────────────────────────────
451
+
452
+
453
+ def get_history_list(
454
+ session: Session,
455
+ process_id: str = "",
456
+ page_index: int = 1,
457
+ page_size: int = 50,
458
+ status: int = 0,
459
+ title: str = "",
460
+ start_date: str = "",
461
+ end_date: str = "",
462
+ instance_id: str = "",
463
+ ) -> dict[str, Any]:
464
+ """Get workflow execution history.
465
+
466
+ Args:
467
+ session: Active session
468
+ process_id: Filter by process
469
+ page_index: Page number
470
+ page_size: Items per page
471
+ status: Status filter (1=running, 2=completed, 3=rejected, 4=failed)
472
+ title: Title search
473
+ start_date: Start date (YYYY-MM-DD)
474
+ end_date: End date (YYYY-MM-DD)
475
+ instance_id: Specific instance ID
476
+
477
+ Returns:
478
+ History list with count
479
+ """
480
+ data: dict[str, Any] = {"pageIndex": page_index, "pageSize": page_size}
481
+ if process_id:
482
+ data["processId"] = process_id
483
+ if status:
484
+ data["status"] = status
485
+ if title:
486
+ data["title"] = title
487
+ if start_date:
488
+ data["startDate"] = start_date
489
+ if end_date:
490
+ data["endDate"] = end_date
491
+ if instance_id:
492
+ data["instanceId"] = instance_id
493
+ result = session.workflow_call("instance/getHistoryList", data)
494
+ if isinstance(result, dict):
495
+ return {
496
+ "data": result.get("data", result.get("list", [])),
497
+ "count": result.get("count", result.get("total", 0)),
498
+ }
499
+ return {"data": result, "count": len(result)}
500
+
501
+
502
+ def get_history_detail(
503
+ session: Session,
504
+ instance_id: str,
505
+ ) -> dict[str, Any]:
506
+ """Get execution history detail.
507
+
508
+ Args:
509
+ session: Active session
510
+ instance_id: Instance ID
511
+
512
+ Returns:
513
+ History detail with node execution info
514
+ """
515
+ return session.workflow_call(
516
+ "instance/getHistoryDetail",
517
+ {"instanceId": instance_id},
518
+ )
519
+
520
+
521
+ # ── Instance Lifecycle ───────────────────────────────────────────────────
522
+
523
+
524
+ def end_instance(session: Session, instance_id: str) -> dict[str, Any]:
525
+ """Terminate a running instance.
526
+
527
+ Args:
528
+ session: Active session
529
+ instance_id: Instance ID
530
+
531
+ Returns:
532
+ Termination result
533
+ """
534
+ return session.workflow_call(
535
+ "v1/instance/endInstance", {"instanceId": instance_id}
536
+ )
537
+
538
+
539
+ def reset_instance(session: Session, instance_id: str) -> dict[str, Any]:
540
+ """Retry a failed instance.
541
+
542
+ Args:
543
+ session: Active session
544
+ instance_id: Instance ID
545
+
546
+ Returns:
547
+ Reset result
548
+ """
549
+ return session.workflow_call(
550
+ "v1/instance/resetInstance", {"instanceId": instance_id}
551
+ )
552
+
553
+
554
+ def restart_instance(
555
+ session: Session,
556
+ instance_id: str,
557
+ work_id: str = "",
558
+ ) -> dict[str, Any]:
559
+ """Re-initiate a rejected/completed instance.
560
+
561
+ Args:
562
+ session: Active session
563
+ instance_id: Instance ID
564
+ work_id: Work item ID
565
+
566
+ Returns:
567
+ Restart result
568
+ """
569
+ return session.workflow_call(
570
+ "instance/restart",
571
+ _build_action_data(instance_id, work_id),
572
+ )