@shulex/cxclawctl 0.1.2 → 0.1.3

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 (208) hide show
  1. package/README.md +25 -22
  2. package/dist/cli.js +2202 -127
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +19 -6
  5. package/capabilities.lock.json +0 -898
  6. package/requirements-cli.txt +0 -2
  7. package/skills/__lib__/__init__.py +0 -0
  8. package/skills/__lib__/skill-runtime/bootstrap.py +0 -134
  9. package/skills/__lib__/solvea-api/__init__.py +0 -0
  10. package/skills/__lib__/solvea-api/client.py +0 -1944
  11. package/skills/__lib__/solvea-api/dashboard.py +0 -100
  12. package/skills/__lib__/solvea-api/solvea_api.py +0 -1341
  13. package/skills/agent-analytics/SKILL.md +0 -74
  14. package/skills/agent-analytics/references/chat-report-fields.md +0 -36
  15. package/skills/agent-analytics/references/report-fields.md +0 -130
  16. package/skills/agent-analytics/references/transcript.md +0 -110
  17. package/skills/agent-builder/SKILL.md +0 -42
  18. package/skills/agent-builder/interfaces/fallback-chatflow.md +0 -47
  19. package/skills/agent-builder/references/chatflow/graph-spec.md +0 -259
  20. package/skills/agent-builder/references/chatflow/node-selection.md +0 -89
  21. package/skills/agent-builder/references/chatflow/nodes/agent.md +0 -350
  22. package/skills/agent-builder/references/chatflow/nodes/business-track.md +0 -43
  23. package/skills/agent-builder/references/chatflow/nodes/code.md +0 -157
  24. package/skills/agent-builder/references/chatflow/nodes/collect-order.md +0 -47
  25. package/skills/agent-builder/references/chatflow/nodes/finish.md +0 -34
  26. package/skills/agent-builder/references/chatflow/nodes/human-review.md +0 -60
  27. package/skills/agent-builder/references/chatflow/nodes/if-else.md +0 -100
  28. package/skills/agent-builder/references/chatflow/nodes/intent.md +0 -79
  29. package/skills/agent-builder/references/chatflow/nodes/knowledge-reply.md +0 -43
  30. package/skills/agent-builder/references/chatflow/nodes/llm.md +0 -117
  31. package/skills/agent-builder/references/chatflow/nodes/note.md +0 -38
  32. package/skills/agent-builder/references/chatflow/nodes/question.md +0 -97
  33. package/skills/agent-builder/references/chatflow/nodes/rag-reply.md +0 -68
  34. package/skills/agent-builder/references/chatflow/nodes/reply.md +0 -97
  35. package/skills/agent-builder/references/chatflow/nodes/start.md +0 -35
  36. package/skills/agent-builder/references/chatflow/nodes/sub-graph.md +0 -48
  37. package/skills/agent-builder/references/chatflow/nodes/tool.md +0 -138
  38. package/skills/agent-builder/references/chatflow/nodes/transfer-to-human.md +0 -63
  39. package/skills/agent-builder/references/chatflow/nodes/variable-assignment.md +0 -52
  40. package/skills/agent-builder/references/chatflow/nodes/variable-extract.md +0 -50
  41. package/skills/agent-builder/references/chatflow/nodes/variable-process.md +0 -70
  42. package/skills/agent-builder/references/chatflow/overview.md +0 -53
  43. package/skills/agent-builder/references/chatflow/visual-translation.md +0 -64
  44. package/skills/agent-builder/references/chatflow/workflow.md +0 -134
  45. package/skills/agent-builder/references/multi-agent/create-update.md +0 -185
  46. package/skills/agent-builder/references/multi-agent/graph-spec.md +0 -246
  47. package/skills/agent-builder/references/multi-agent/graph-structure.md +0 -12
  48. package/skills/agent-builder/references/multi-agent/migrate-to-chatflow.md +0 -13
  49. package/skills/agent-builder/references/multi-agent/migration/large.md +0 -554
  50. package/skills/agent-builder/references/multi-agent/migration/principles.md +0 -446
  51. package/skills/agent-builder/references/multi-agent/migration/small.md +0 -225
  52. package/skills/agent-builder/references/multi-agent/orchestration.md +0 -11
  53. package/skills/agent-builder/references/multi-agent/overview.md +0 -48
  54. package/skills/agent-builder/references/multi-agent/update.md +0 -128
  55. package/skills/agent-builder/references/multi-agent/workflow.md +0 -87
  56. package/skills/agent-builder/references/single-agent/overview.md +0 -48
  57. package/skills/agent-builder/references/single-agent/prompt.md +0 -16
  58. package/skills/agent-builder/references/single-agent/tools.md +0 -36
  59. package/skills/agent-builder/references/single-agent/voice.md +0 -46
  60. package/skills/agent-builder/references/tools/http-tool.md +0 -315
  61. package/skills/agent-builder/references/tools/mock-tool.md +0 -279
  62. package/skills/agent-builder/references/tools/overview.md +0 -46
  63. package/skills/agent-builder/references/tools/tool-config.md +0 -43
  64. package/skills/agent-builder/references/tools/x-token.md +0 -34
  65. package/skills/agent-builder/scripts/chatflow/chatflow_builder.py +0 -3458
  66. package/skills/agent-builder/scripts/chatflow/validate_graph.py +0 -1697
  67. package/skills/agent-builder/scripts/copy_marketplace_agent.py +0 -61
  68. package/skills/agent-builder/scripts/multi-agent/legacy_graph_analyzer.py +0 -5974
  69. package/skills/agent-builder/scripts/multi-agent/replay_compare.py +0 -679
  70. package/skills/agent-builder/scripts/patch_agent_tools.py +0 -135
  71. package/skills/agent-builder/scripts/tools/validate_tool_config.py +0 -384
  72. package/skills/agent-tester/SKILL.md +0 -35
  73. package/skills/agent-tester/batch-test/overview.md +0 -86
  74. package/skills/agent-tester/scripts/batch_test_sheet.py +0 -213
  75. package/skills/agent-tester/single-test/badcase-retest.md +0 -85
  76. package/skills/agent-tester/single-test/direct-test.md +0 -24
  77. package/skills/agent-tester/single-test/overview.md +0 -142
  78. package/skills/delivery/SKILL.md +0 -112
  79. package/skills/delivery/interfaces/classify.md +0 -38
  80. package/skills/delivery/interfaces/create-agents.md +0 -89
  81. package/skills/delivery/interfaces/delivery-test.md +0 -67
  82. package/skills/delivery/references/flow.md +0 -40
  83. package/skills/delivery/references/validation.md +0 -15
  84. package/skills/delivery/scripts/batch_test.py +0 -704
  85. package/skills/delivery/scripts/classify.py +0 -22
  86. package/skills/delivery/scripts/create_agents.py +0 -695
  87. package/skills/delivery/scripts/gen_delivery_report.py +0 -335
  88. package/skills/delivery/scripts/gen_excel.py +0 -234
  89. package/skills/delivery/scripts/gen_report.py +0 -208
  90. package/skills/delivery/scripts/plan.py +0 -163
  91. package/skills/delivery/scripts/render.py +0 -713
  92. package/skills/delivery/scripts/render_summary.py +0 -38
  93. package/skills/delivery/scripts/sample_history_cases.py +0 -109
  94. package/skills/kb-builder/SKILL.md +0 -80
  95. package/skills/kb-builder/interfaces/qa-upload.md +0 -55
  96. package/skills/kb-builder/interfaces/web-kb.md +0 -84
  97. package/skills/kb-builder/references/directory.md +0 -373
  98. package/skills/kb-builder/references/export.md +0 -282
  99. package/skills/kb-builder/references/isolation-keywords.md +0 -113
  100. package/skills/kb-builder/references/knowledge.md +0 -153
  101. package/skills/kb-builder/references/product.md +0 -52
  102. package/skills/kb-builder/references/qa-from-help-center.md +0 -58
  103. package/skills/kb-builder/references/qa-from-pdf.md +0 -94
  104. package/skills/kb-builder/references/qa-from-tickets.md +0 -168
  105. package/skills/kb-builder/references/qa-from-web.md +0 -98
  106. package/skills/kb-builder/references/qa-quality.md +0 -73
  107. package/skills/kb-builder/references/reply-template.md +0 -237
  108. package/skills/kb-builder/references/tag-isolation-migration.md +0 -61
  109. package/skills/kb-builder/references/tags.md +0 -45
  110. package/skills/kb-builder/references/upload.md +0 -130
  111. package/skills/kb-builder/scripts/batch_extract_ticket_qa.py +0 -333
  112. package/skills/kb-builder/scripts/build_directory_plan.py +0 -144
  113. package/skills/kb-builder/scripts/crawl_site.py +0 -433
  114. package/skills/kb-builder/scripts/create_dirs.py +0 -146
  115. package/skills/kb-builder/scripts/export_knowledge.py +0 -454
  116. package/skills/kb-builder/scripts/extract_ticket_qa.py +0 -441
  117. package/skills/kb-builder/scripts/extract_web_qa.py +0 -118
  118. package/skills/kb-builder/scripts/import_qa.py +0 -219
  119. package/skills/kb-builder/scripts/import_source_documents.py +0 -143
  120. package/skills/kb-builder/scripts/import_templates.py +0 -409
  121. package/skills/poc/SKILL.md +0 -125
  122. package/skills/poc/assets/default_manual.css +0 -279
  123. package/skills/poc/assets/notice_escalate.png +0 -0
  124. package/skills/poc/assets/notice_escalate2.png +0 -0
  125. package/skills/poc/assets/notice_new_chat.png +0 -0
  126. package/skills/poc/assets/poc_test_template.html +0 -645
  127. package/skills/poc/assets/poc_test_template.md +0 -104
  128. package/skills/poc/assets/step3_preview.png +0 -0
  129. package/skills/poc/assets/step4_order_note.png +0 -0
  130. package/skills/poc/interfaces/classify.md +0 -38
  131. package/skills/poc/interfaces/create-agents.md +0 -108
  132. package/skills/poc/interfaces/poc-test.md +0 -94
  133. package/skills/poc/references/flow.md +0 -47
  134. package/skills/poc/references/kb-directory.md +0 -22
  135. package/skills/poc/references/validation.md +0 -17
  136. package/skills/poc/scripts/classify.py +0 -22
  137. package/skills/poc/scripts/create_agents.py +0 -818
  138. package/skills/poc/scripts/gen_excel.py +0 -234
  139. package/skills/poc/scripts/gen_poc_manual.py +0 -249
  140. package/skills/poc/scripts/gen_report.py +0 -208
  141. package/skills/poc/scripts/inspect_chatflow.py +0 -209
  142. package/skills/poc/scripts/plan.py +0 -178
  143. package/skills/poc/scripts/poc_test.py +0 -495
  144. package/skills/poc/scripts/render.py +0 -713
  145. package/skills/poc/scripts/render_summary.py +0 -41
  146. package/skills/runtime-inspector/SKILL.md +0 -51
  147. package/skills/runtime-inspector/references/frontend-rendering.md +0 -126
  148. package/skills/runtime-inspector/references/model.md +0 -59
  149. package/skills/runtime-inspector/references/sandbox.md +0 -131
  150. package/skills/runtime-inspector/scripts/model_inspect.py +0 -68
  151. package/skills/runtime-inspector/scripts/prepare.py +0 -98
  152. package/skills/runtime-inspector/scripts/process.py +0 -84
  153. package/skills/runtime-inspector/scripts/read_state.py +0 -32
  154. package/skills/runtime-inspector/scripts/sandbox_inspect.py +0 -463
  155. package/skills/runtime-inspector/scripts/test_claude_proxy.py +0 -49
  156. package/skills/runtime-inspector/scripts/test_openai_proxy.py +0 -41
  157. package/skills/runtime-inspector/scripts/verify_persistence.py +0 -101
  158. package/skills/runtime-inspector/scripts/write_test.py +0 -41
  159. package/skills/setup/SKILL.md +0 -17
  160. package/skills/shulex-support/SKILL.md +0 -39
  161. package/skills/shulex-support/references/badcase-analysis/overview.md +0 -34
  162. package/skills/shulex-support/references/badcase-analysis/text/conversation-record.md +0 -105
  163. package/skills/shulex-support/references/badcase-analysis/text/core-flow.md +0 -89
  164. package/skills/shulex-support/references/badcase-analysis/text/log-query-rules.md +0 -36
  165. package/skills/shulex-support/references/badcase-analysis/text/m1-entry.md +0 -53
  166. package/skills/shulex-support/references/badcase-analysis/text/m10-chatflow-service.md +0 -259
  167. package/skills/shulex-support/references/badcase-analysis/text/m11-algorithm-service.md +0 -148
  168. package/skills/shulex-support/references/badcase-analysis/text/m12-quality-inspection.md +0 -57
  169. package/skills/shulex-support/references/badcase-analysis/text/m2-intent.md +0 -120
  170. package/skills/shulex-support/references/badcase-analysis/text/m3-strategy.md +0 -126
  171. package/skills/shulex-support/references/badcase-analysis/text/m4-aifield.md +0 -121
  172. package/skills/shulex-support/references/badcase-analysis/text/m5-agent.md +0 -208
  173. package/skills/shulex-support/references/badcase-analysis/text/m6-tool.md +0 -115
  174. package/skills/shulex-support/references/badcase-analysis/text/m7-reply.md +0 -72
  175. package/skills/shulex-support/references/badcase-analysis/text/m8-error.md +0 -92
  176. package/skills/shulex-support/references/badcase-analysis/text/m9-knowledge-search.md +0 -147
  177. package/skills/shulex-support/references/badcase-analysis/text/sls-query.md +0 -283
  178. package/skills/shulex-support/references/badcase-analysis/voice/core-flow.md +0 -77
  179. package/skills/shulex-support/references/badcase-analysis/voice/dependencies.md +0 -19
  180. package/skills/shulex-support/references/badcase-analysis/voice/platform-api.md +0 -23
  181. package/skills/shulex-support/references/badcase-analysis/voice/sls-playbook.md +0 -31
  182. package/skills/shulex-support/references/product-docs.md +0 -70
  183. package/skills/shulex-support/references/tickets.md +0 -184
  184. package/skills/shulex-support/scripts/support.py +0 -427
  185. package/skills/solvea-desk/SKILL.md +0 -39
  186. package/skills/solvea-desk/references/report/fields.md +0 -82
  187. package/skills/solvea-desk/references/report/report-design.md +0 -200
  188. package/skills/solvea-desk/references/report/report-template.html +0 -44
  189. package/skills/solvea-desk/references/report/report.css +0 -517
  190. package/skills/solvea-desk/references/report/workflow.md +0 -464
  191. package/skills/solvea-desk/references/tickets/query.md +0 -103
  192. package/skills/solvea-desk/references/tickets/tags.md +0 -83
  193. package/skills/solvea-desk/scripts/report/fetch_sources.py +0 -580
  194. package/skills/solvea-desk/scripts/report/render_report.py +0 -763
  195. package/skills/solvea-desk/scripts/tickets/desk_api.py +0 -73
  196. package/skills/solvea-desk/scripts/tickets/fetch_tickets.py +0 -403
  197. package/skills/solvea-desk/scripts/tickets/ticket_tags.py +0 -305
  198. package/skills/solvea-kit/SKILL.md +0 -84
  199. package/skills/solvea-kit/references/agent.md +0 -145
  200. package/skills/solvea-kit/references/chat.md +0 -244
  201. package/skills/solvea-kit/references/intent.md +0 -69
  202. package/skills/solvea-kit/references/plugin.md +0 -53
  203. package/skills/solvea-kit/references/quality-inspection.md +0 -75
  204. package/skills/solvea-kit/references/strategy.md +0 -62
  205. package/skills/solvea-kit/references/tagging.md +0 -231
  206. package/skills/solvea-kit/references/variables.md +0 -53
  207. package/skills/solvea-kit/scripts/generate_label_import_file.py +0 -151
  208. package/skills/solvea-kit/scripts/intent_classify.py +0 -843
@@ -1,208 +0,0 @@
1
- """
2
- HTML report generator for delivery skill.
3
-
4
- Reads classification results (workspace/state/delivery/progress.json -> results_path) and
5
- renders a polished HTML report under workspace/outputs/delivery/.
6
-
7
- Usage:
8
- python3 scripts/gen_report.py [--brand "Acme"]
9
- """
10
-
11
- import os, sys
12
- sys.path.insert(0, os.path.join(os.environ.get("SOLVEA_LIB_DIR", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "__lib__"))), "skill-runtime"))
13
- from bootstrap import *
14
-
15
- import json, argparse
16
- from uuid import uuid4
17
-
18
-
19
- def _read_state() -> dict:
20
- _sf = STATE_DIR / "progress.json"
21
- if _sf.exists():
22
- try:
23
- return json.loads(_sf.read_text(encoding="utf-8"))
24
- except Exception:
25
- pass
26
- return {}
27
-
28
-
29
- def _write_state(data: dict) -> None:
30
- _sf = STATE_DIR / "progress.json"
31
- _sf.parent.mkdir(parents=True, exist_ok=True)
32
- _sf.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
33
-
34
- from render import render_html
35
-
36
- COLOR_PALETTE = [
37
- "#ef4444", "#f97316", "#eab308", "#22c55e",
38
- "#14b8a6", "#3b82f6", "#8b5cf6", "#ec4899",
39
- "#06b6d4", "#84cc16",
40
- ]
41
-
42
- CIRCLE_NUMS = "①②③④⑤⑥⑦⑧⑨⑩"
43
-
44
-
45
- def build_config_from_results(results, brand_name=""):
46
- def uid():
47
- return uuid4().hex
48
-
49
- agents = []
50
- all_intents = results.get("intents", []) + results.get("new_intents", [])
51
- meta = results.get("meta", {})
52
- total = meta.get("total", 0)
53
-
54
- for i, intent in enumerate(all_intents):
55
- sub_intents = intent.get("sub_intents", [])
56
- is_new = intent.get("is_new", False)
57
- agent_id = f"intent-{i}"
58
-
59
- l2_nodes = []
60
- for j, s in enumerate(sub_intents):
61
- sample_preview = s["samples"][0][:50] + "..." if s.get("samples") else ""
62
- l2_nodes.append({
63
- "id": f"n2-{uid()[:8]}",
64
- "name": s["name"],
65
- "desc": f"{s['pct']:.1f}% — {sample_preview}" if sample_preview else f"{s['pct']:.1f}%",
66
- "count": s["count"],
67
- "definition": s.get("definition", ""),
68
- "is_shared": False,
69
- "shared_agents": [],
70
- "samples": s.get("samples", []),
71
- })
72
-
73
- nodes_ac = []
74
- for s in sub_intents[:3]:
75
- nodes_ac.append({
76
- "name": f"节点 · {s['name']}",
77
- "trigger": f"客户投诉:{s['name']}",
78
- "action": f"<code>LLM</code> 处理 {s['name']},引导解决",
79
- })
80
-
81
- agents.append({
82
- "id": agent_id,
83
- "name": f"{CIRCLE_NUMS[i % len(CIRCLE_NUMS)]} {intent['name']}",
84
- "color": COLOR_PALETTE[i % len(COLOR_PALETTE)],
85
- "l1_intents": [intent["name"]],
86
- "total_count": intent["count"],
87
- "total_pct": intent["pct"],
88
- "is_new": is_new,
89
- "intent_config": {
90
- "definition": intent.get("definition", ""),
91
- "excludes": [],
92
- "examples": intent.get("samples", [])[:3],
93
- "covers": [s["name"] for s in sub_intents],
94
- },
95
- "agent_config": {
96
- "type": "chatflow",
97
- "nodes": nodes_ac,
98
- "footer": f"<b>结束:</b>解决{intent['name']}问题 / 转人工",
99
- },
100
- "l2_nodes": l2_nodes,
101
- })
102
-
103
- edges = []
104
- for a in agents:
105
- ag_html_id = f"ag-{a['id'].replace('_', '-')}"
106
- color = a.get("color", "#6b7280")
107
- for node in a["l2_nodes"]:
108
- count = node.get("count", 0)
109
- if count > 0:
110
- edges.append({"from": ag_html_id, "to": node["id"], "count": count, "color": color})
111
-
112
- total_nodes = sum(len(a["l2_nodes"]) for a in agents)
113
- n_known = meta.get("n_known", len(results.get("intents", [])))
114
- n_new = meta.get("n_new", len(results.get("new_intents", [])))
115
-
116
- rows = []
117
- for a in agents:
118
- n = len(a["l2_nodes"])
119
- badge = f"{n} 节点 ✓" if n <= 2 else (f"{n} 节点 ⚠️" if n <= 3 else f"{n} 节点 ❌")
120
- rows.append({
121
- "agent_name": a["name"],
122
- "color": a["color"],
123
- "node_count": n,
124
- "badge": badge,
125
- })
126
-
127
- l2_total = sum(s["count"] for intent in all_intents for s in intent.get("sub_intents", []))
128
- opt_notes = (
129
- f"✅ 已知意图 {n_known} 个,新发现意图 {n_new} 个,共 {n_known + n_new} 个 L1 意图\n\n"
130
- f"📊 数据基础:{total:,} 条对话 / L2 分类:{l2_total:,} 条"
131
- )
132
- if n_new > 0:
133
- new_names = [i["name"] for i in results.get("new_intents", [])]
134
- opt_notes += f"\n\n⚡ 新发现意图:{' · '.join(new_names)}"
135
-
136
- return {
137
- "agents": agents,
138
- "filter_block": {"types": ["未分类投诉"], "count": 0},
139
- "node_summary": {
140
- "rows": rows,
141
- "total_nodes": total_nodes,
142
- "optimization_notes": opt_notes,
143
- },
144
- "shared_nodes": [],
145
- "edges": edges,
146
- }
147
-
148
-
149
- def _resolve_results_path(state: dict) -> str:
150
- path = state.get("results_path")
151
- if not path:
152
- raise FileNotFoundError(
153
- "No results_path in state. Run classify.py first."
154
- )
155
- if not os.path.exists(path):
156
- raise FileNotFoundError(
157
- f"Results file missing: {path}. Run classify.py first."
158
- )
159
- return path
160
-
161
-
162
- def main():
163
- parser = argparse.ArgumentParser(description="Generate delivery intent classification HTML report")
164
- parser.add_argument("--brand", default="")
165
- parser.add_argument("--results", default=None,
166
- help="Override results JSON path (default: read from progress.json)")
167
- args = parser.parse_args()
168
-
169
- if args.results:
170
- results_path = args.results
171
- if not os.path.exists(results_path):
172
- raise FileNotFoundError(f"Results file missing: {results_path}")
173
- else:
174
- state = _read_state()
175
- results_path = _resolve_results_path(state)
176
-
177
- with open(results_path) as f:
178
- results = json.load(f)
179
-
180
- config = build_config_from_results(results, brand_name=args.brand)
181
-
182
- meta = results.get("meta", {})
183
- data_compat = {
184
- "_meta": {"total": meta.get("total", 0), "brand": args.brand},
185
- "tree": {},
186
- "turn_distribution": {},
187
- "fuzzy_samples": {},
188
- }
189
-
190
- project_id = os.environ.get("SOLVEA_PROJECT_ID", "")
191
- html = render_html(config, data_compat, brand=args.brand, project_id=project_id)
192
-
193
- OUTPUTS_DIR.mkdir(parents=True, exist_ok=True)
194
- report_path = str(OUTPUTS_DIR / f"report_{timestamp()}.html")
195
- with open(report_path, "w", encoding="utf-8") as f:
196
- f.write(html)
197
- print(f"[gen_report] Report -> {report_path}")
198
-
199
- state = _read_state()
200
- state["report_path"] = report_path
201
- state["updated_at"] = timestamp()
202
- _write_state(state)
203
-
204
- print(f"[gen_report] Done.")
205
-
206
-
207
- if __name__ == "__main__":
208
- main()
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Delivery 顶层状态规划器。
3
-
4
- 只维护 `/workspace/state/delivery/progress.json`,不执行 intent / KB / batch
5
- 等底层能力。其他 skill 的状态只通过路径引用记录在本文件中。
6
- """
7
- import os, sys
8
- sys.path.insert(0, os.path.join(os.environ.get("SOLVEA_LIB_DIR", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "__lib__"))), "skill-runtime"))
9
- from bootstrap import * # noqa: F401,F403
10
-
11
- import argparse
12
- import json
13
- from datetime import datetime, timezone
14
- from typing import Any
15
-
16
-
17
- STATE_FILE = STATE_DIR / "progress.json"
18
-
19
- STATUS_ORDER = [
20
- "empty",
21
- "classified",
22
- "agents_created",
23
- "kb_done",
24
- "regression_done",
25
- "done",
26
- ]
27
-
28
-
29
- def default_state() -> dict[str, Any]:
30
- return {
31
- "status": "empty",
32
- "tenant": SOLVEA_TENANT_ID or "",
33
- "brand_name": "",
34
- "intent": {
35
- "progress_path": "/workspace/state/delivery/progress.json",
36
- "classification_report_path": "",
37
- "classification_excel_path": "",
38
- "created_log_path": "",
39
- },
40
- "kb": {
41
- "required": True,
42
- "source_url": "",
43
- "directory_plan_path": "",
44
- "qa_plan_path": "",
45
- "upload_result_path": "",
46
- },
47
- "regression": {
48
- "input_path": "",
49
- "touch_point": "LIVE_CHAT",
50
- "results_path": "",
51
- "report_html": "",
52
- "report_md": "",
53
- },
54
- "updated_at": "",
55
- }
56
-
57
-
58
- def merge_dict(base: dict[str, Any], patch: dict[str, Any]) -> None:
59
- for key, value in patch.items():
60
- if isinstance(value, dict) and isinstance(base.get(key), dict):
61
- merge_dict(base[key], value)
62
- else:
63
- base[key] = value
64
-
65
-
66
- def read_state() -> dict[str, Any]:
67
- if not STATE_FILE.exists():
68
- return default_state()
69
- try:
70
- loaded = json.loads(STATE_FILE.read_text(encoding="utf-8"))
71
- except Exception:
72
- return default_state()
73
- state = default_state()
74
- merge_dict(state, loaded)
75
- return state
76
-
77
-
78
- def write_state(state: dict[str, Any]) -> None:
79
- state["updated_at"] = datetime.now(timezone.utc).isoformat()
80
- STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
81
- STATE_FILE.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")
82
-
83
-
84
- def set_path(state: dict[str, Any], dotted_key: str, raw_value: str) -> None:
85
- parts = [p for p in dotted_key.split(".") if p]
86
- if not parts:
87
- raise ValueError("empty key")
88
- cur = state
89
- for part in parts[:-1]:
90
- nxt = cur.get(part)
91
- if not isinstance(nxt, dict):
92
- nxt = {}
93
- cur[part] = nxt
94
- cur = nxt
95
- value: Any = raw_value
96
- if raw_value.lower() == "true":
97
- value = True
98
- elif raw_value.lower() == "false":
99
- value = False
100
- elif raw_value.startswith("[") or raw_value.startswith("{"):
101
- value = json.loads(raw_value)
102
- cur[parts[-1]] = value
103
-
104
-
105
- def recommendation(status: str) -> str:
106
- return {
107
- "empty": "下一步:读取 delivery/interfaces/classify.md,确认从 xlsx 分类还是固定 7 意图开始。",
108
- "classified": "下一步:展示分类结果并等待用户确认;确认后调用 /skills/delivery/scripts/create_agents.py --mode delivery。",
109
- "agents_created": "下一步:进入 KB 阶段;如用户声称已有 KB,先 list-directories / list-knowledge 验证。",
110
- "kb_done": "下一步:读取 delivery/interfaces/delivery-test.md,确认回归数据来源和 touch-point。",
111
- "regression_done": "下一步:汇总 KPI 报告和失败明细,确认交付完成。",
112
- "done": "当前 Delivery 已完成;如需重跑,请明确要重跑的阶段。",
113
- }.get(status, "状态未知:请检查 progress.json。")
114
-
115
-
116
- def main() -> None:
117
- parser = argparse.ArgumentParser(description="Delivery top-level progress planner")
118
- parser.add_argument("--init", action="store_true", help="Create progress.json if missing")
119
- parser.add_argument("--status", choices=STATUS_ORDER, help="Update top-level status")
120
- parser.add_argument("--tenant", default=None)
121
- parser.add_argument("--brand-name", default=None)
122
- parser.add_argument("--set", action="append", default=[], metavar="KEY=VALUE",
123
- help="Set a dotted state path, e.g. intent.created_log_path=/workspace/...")
124
- parser.add_argument("--json", action="store_true", help="Print JSON only")
125
- args = parser.parse_args()
126
-
127
- existed = STATE_FILE.exists()
128
- state = read_state()
129
- changed = False
130
-
131
- if args.init and not existed:
132
- changed = True
133
- if args.status:
134
- state["status"] = args.status
135
- changed = True
136
- if args.tenant is not None:
137
- state["tenant"] = args.tenant
138
- changed = True
139
- if args.brand_name is not None:
140
- state["brand_name"] = args.brand_name
141
- changed = True
142
- for item in args.set:
143
- if "=" not in item:
144
- raise SystemExit(f"--set expects KEY=VALUE, got: {item}")
145
- key, value = item.split("=", 1)
146
- set_path(state, key, value)
147
- changed = True
148
-
149
- if changed:
150
- write_state(state)
151
-
152
- if args.json:
153
- print(json.dumps(state, ensure_ascii=False, indent=2))
154
- return
155
-
156
- print(f"Delivery progress: {STATE_FILE}")
157
- print(f"status={state.get('status')} tenant={state.get('tenant') or '-'} brand={state.get('brand_name') or '-'}")
158
- print(recommendation(str(state.get("status") or "")))
159
- print(json.dumps(state, ensure_ascii=False, indent=2))
160
-
161
-
162
- if __name__ == "__main__":
163
- main()