@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
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { readFile } from "fs/promises";
4
+ import { readFile as readFile5 } from "fs/promises";
5
5
 
6
6
  // src/auth.ts
7
7
  import open from "open";
@@ -9,27 +9,37 @@ import open from "open";
9
9
  // package.json
10
10
  var package_default = {
11
11
  name: "@shulex/cxclawctl",
12
- version: "0.1.2",
12
+ version: "0.1.3",
13
13
  description: "Solvea CXClaw CLI and Codex plugin runtime",
14
14
  type: "module",
15
- bin: { cxclawctl: "./bin/cxclawctl.mjs" },
16
- files: ["bin", "dist/cli.js", "dist/cli.js.map", "skills", "capabilities.lock.json", "requirements-cli.txt"],
15
+ bin: {
16
+ cxclawctl: "./bin/cxclawctl.mjs"
17
+ },
18
+ files: [
19
+ "bin",
20
+ "dist/cli.js",
21
+ "dist/cli.js.map"
22
+ ],
17
23
  scripts: {
18
24
  build: "tsup",
19
25
  dev: "tsx src/cli.ts",
20
26
  typecheck: "tsc --noEmit",
21
27
  test: "bun test --path-ignore-patterns _tmp_",
22
- "check:capabilities": "python3 scripts/check_capabilities.py",
28
+ "check:capabilities": "tsx scripts/check-capabilities.ts",
23
29
  "check:release": "tsx scripts/check-release.ts",
30
+ "test:package": "tsx scripts/test-packed-package.ts",
24
31
  "release:prepare": "tsx scripts/prepare-release.ts",
25
32
  "package:agent-plugin": "node scripts/package-agent-plugin.mjs",
26
33
  "package:codex-plugin": "node scripts/package-codex-plugin.mjs"
27
34
  },
28
- engines: { node: ">=22" },
35
+ engines: {
36
+ node: ">=22"
37
+ },
29
38
  dependencies: {
30
39
  "@alicloud/log": "^1.2.6",
31
40
  "@napi-rs/keyring": "^2.1.2",
32
41
  "compare-versions": "^6.1.1",
42
+ exceljs: "^4.4.0",
33
43
  open: "^10.2.0"
34
44
  },
35
45
  devDependencies: {
@@ -39,7 +49,10 @@ var package_default = {
39
49
  tsx: "^4.21.0",
40
50
  typescript: "^5.9.0"
41
51
  },
42
- repository: { type: "git", url: "git+https://github.com/SolveaCX/cx_claw_codex.git" },
52
+ repository: {
53
+ type: "git",
54
+ url: "git+https://github.com/SolveaCX/cx_claw_codex.git"
55
+ },
43
56
  license: "UNLICENSED"
44
57
  };
45
58
 
@@ -85,7 +98,7 @@ var options = process.platform === "linux" ? { linux: { store: "secret-service"
85
98
  var entry = () => new AsyncEntry("com.solvea.cxclaw", "session", options);
86
99
  async function loadSession() {
87
100
  const raw = await entry().getPassword();
88
- if (!raw) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u8FD0\u884C npx --yes @shulex/cxclawctl@latest auth login");
101
+ if (!raw) throw new Error("\u672A\u767B\u5F55\uFF0C\u8BF7\u5148\u8FD0\u884C cxclawctl auth login");
89
102
  return JSON.parse(raw);
90
103
  }
91
104
  async function saveSession(session) {
@@ -147,61 +160,932 @@ function option(args, name, required = false) {
147
160
  if (required && !value) throw new Error(`${name} is required`);
148
161
  return value;
149
162
  }
163
+ function options2(args, name) {
164
+ const values = [];
165
+ for (let index = 0; index < args.length; index += 1) {
166
+ if (args[index] === name && args[index + 1] && !args[index + 1].startsWith("-")) values.push(args[index + 1]);
167
+ }
168
+ return values;
169
+ }
170
+ function optionList(args, name) {
171
+ const index = args.indexOf(name);
172
+ if (index < 0) return [];
173
+ const values = [];
174
+ for (let cursor = index + 1; cursor < args.length && !args[cursor].startsWith("-"); cursor += 1) values.push(args[cursor]);
175
+ return values;
176
+ }
150
177
  function flag(args, name) {
151
178
  return args.includes(name);
152
179
  }
153
180
  function positionals(args) {
154
181
  const out = [];
155
- for (let i = 0; i < args.length; i++) {
156
- if (args[i].startsWith("--")) {
157
- if (!["--pretty", "--reverse", "--scheduled", "--install-scheduler"].includes(args[i])) i++;
158
- } else out.push(args[i]);
182
+ for (let index = 0; index < args.length; index += 1) {
183
+ if (args[index].startsWith("--")) {
184
+ if (!["--pretty", "--reverse", "--scheduled", "--install-scheduler"].includes(args[index])) index += 1;
185
+ } else out.push(args[index]);
159
186
  }
160
187
  return out;
161
188
  }
162
189
 
163
190
  // src/business.ts
164
- import { spawn } from "child_process";
165
- import { access } from "fs/promises";
166
- import { dirname, join, normalize, relative, resolve } from "path";
191
+ import { dirname, resolve } from "path";
167
192
  import { fileURLToPath } from "url";
168
- var packageRoot = () => resolve(dirname(fileURLToPath(import.meta.url)), "..");
169
- async function python() {
170
- for (const name of ["python3.12", "python3"]) {
171
- const ok = await new Promise((r) => {
172
- const p = spawn(name, ["-c", "import sys;raise SystemExit(sys.version_info[:2]!=(3,12))"], { stdio: "ignore" });
173
- p.on("error", () => r(false));
174
- p.on("exit", (c) => r(c === 0));
193
+
194
+ // src/solvea/commands.ts
195
+ import { readFile as readFile2 } from "fs/promises";
196
+
197
+ // src/solvea/client.ts
198
+ var SolveaClient = class {
199
+ constructor(session) {
200
+ this.session = session;
201
+ if (!session.tenant?.businessUrl || !session.tenant.businessToken) {
202
+ throw new Error("no tenant selected; run tenant use before a business command");
203
+ }
204
+ }
205
+ session;
206
+ project;
207
+ bot;
208
+ get baseUrl() {
209
+ return this.session.tenant.businessUrl.replace(/\/$/, "");
210
+ }
211
+ get env() {
212
+ return this.session.tenant.environment;
213
+ }
214
+ async request(method, path, body, query2) {
215
+ const url = new URL(`${this.baseUrl}${path}`);
216
+ for (const [key, value] of Object.entries(query2 ?? {})) url.searchParams.set(key, String(value));
217
+ const cookie = this.env === "prod" ? "_token" : "_token_staging";
218
+ const headers = new Headers({
219
+ accept: "application/json, text/plain, */*",
220
+ origin: this.baseUrl,
221
+ referer: `${this.baseUrl}/chatbot`,
222
+ cookie: `${cookie}=${this.session.tenant.businessToken}`,
223
+ "x-cxclaw-client-version": process.env.CXCLAW_PLUGIN_VERSION ?? "unknown"
175
224
  });
176
- if (ok) return name;
177
- }
178
- throw new Error("Python 3.12 is required for CXClaw business scripts");
179
- }
180
- async function runPython(script, args, session) {
181
- const root = packageRoot(), target = resolve(root, normalize(script.replace(/^[/\\]+/, "")));
182
- if (!relative(join(root, "skills"), target) || relative(join(root, "skills"), target).startsWith("..")) throw new Error("script path must be inside skills/");
183
- await access(target);
184
- const command = await python();
185
- const env = { ...process.env, PYTHONPATH: join(root, "skills", "__lib__") };
186
- if (session?.tenant) Object.assign(env, { SOLVEA_ENV: session.tenant.environment, SOLVEA_BASE_URL: session.tenant.businessUrl, SOLVEA_PROD_URL: session.tenant.businessUrl, SOLVEA_TOKEN: session.tenant.businessToken, SOLVEA_PROD_TOKEN: session.tenant.businessToken });
187
- return await new Promise((done, reject) => {
188
- const child = spawn(command, [target, ...args], { stdio: "inherit", env });
189
- child.on("error", reject);
190
- child.on("exit", (code) => done(code ?? 1));
191
- });
225
+ if (body !== void 0) headers.set("content-type", "application/json");
226
+ let last;
227
+ for (let attempt = 0; attempt < 3; attempt += 1) {
228
+ try {
229
+ const response = await fetch(url, {
230
+ method,
231
+ headers,
232
+ body: body === void 0 ? void 0 : JSON.stringify(body),
233
+ signal: AbortSignal.timeout(3e4)
234
+ });
235
+ const text = await response.text();
236
+ let value;
237
+ try {
238
+ value = text ? JSON.parse(text) : void 0;
239
+ } catch {
240
+ value = { raw: text };
241
+ }
242
+ if (!response.ok) throw new Error(`HTTP ${response.status} ${method} ${path}: ${text}`);
243
+ if (value && typeof value === "object" && !Array.isArray(value)) {
244
+ const object = value;
245
+ const code = object.code ?? object.errno;
246
+ if (code !== void 0 && ![0, "0", 200, "200", "OK", "SUCCESS"].includes(code)) {
247
+ throw new Error(`API error ${method} ${path}: ${String(object.msg ?? object.message ?? object.error ?? code)}`);
248
+ }
249
+ if (object.success === false) throw new Error(`API error ${method} ${path}: ${String(object.msg ?? object.message ?? object.error ?? "request failed")}`);
250
+ }
251
+ return value;
252
+ } catch (error) {
253
+ last = error;
254
+ if (attempt < 2) await new Promise((resolve5) => setTimeout(resolve5, 200 * 2 ** attempt));
255
+ }
256
+ }
257
+ throw last;
258
+ }
259
+ async post(path, body) {
260
+ return this.request("POST", path, body);
261
+ }
262
+ async get(path, query2) {
263
+ return this.request("GET", path, void 0, query2);
264
+ }
265
+ async put(path, body) {
266
+ return this.request("PUT", path, body);
267
+ }
268
+ async rawCall(method, path, body, query2) {
269
+ return this.request(method, path, body, query2);
270
+ }
271
+ safePathSegment(value, name) {
272
+ if (!value || value === "." || value === ".." || /[\\/?#%\u0000-\u001f\u007f]/.test(value)) {
273
+ throw new Error(`${name} must be a safe non-empty path segment`);
274
+ }
275
+ return encodeURIComponent(value);
276
+ }
277
+ async projectInfo() {
278
+ return this.get("/api_v2/gpt/bots");
279
+ }
280
+ async projectId() {
281
+ if (!this.project) {
282
+ const rows = await this.projectInfo();
283
+ const first = Array.isArray(rows) ? rows[0] : void 0;
284
+ this.project = String(first?.projectId ?? 950);
285
+ this.bot = String(first?.id ?? "");
286
+ }
287
+ return this.project;
288
+ }
289
+ async botId() {
290
+ if (!this.bot) await this.projectId();
291
+ return this.bot || "723";
292
+ }
293
+ async listAgents(category = "text") {
294
+ return this.post("/api_v2/gpt/ap/queryAgent", { projectId: Number(await this.projectId()), needRelation: true, noMeta: true, category });
295
+ }
296
+ async getAgent(id) {
297
+ return this.post("/api_v2/gpt/ap/queryAgent", { projectId: Number(await this.projectId()), agentId: Number(id), needRelation: true, squareAgent: false });
298
+ }
299
+ async getChatflowGraph(id) {
300
+ return this.post("/api_v2/gpt/chatflow/queryGraph/latest", { agentId: Number(id) });
301
+ }
302
+ async createAgent(data3) {
303
+ return this.post("/api_v2/gpt/ap/createAgent", { projectId: Number(await this.projectId()), ...data3 });
304
+ }
305
+ async updateAgent(data3) {
306
+ return this.post("/api_v2/gpt/ap/updateAgent", data3);
307
+ }
308
+ async updateChatflow(agentId, graph, publish = false) {
309
+ const current = await this.getAgent(agentId);
310
+ const agent = Array.isArray(current) ? current[0] : current;
311
+ if (!agent || agent.type !== "CHAT_FLOW") throw new Error(`Agent ${agentId} is not CHAT_FLOW`);
312
+ const payload = { ...agent, agentId: agent.id ?? Number(agentId), meta: { ...agent.meta ?? {}, chatFlowGraph: graph } };
313
+ return this.updateAgent({ ...payload, ...publish ? { publish: true } : {} });
314
+ }
315
+ async listPlugins() {
316
+ return this.post("/api_v2/gpt/ap/queryPlugin", { projectId: Number(await this.projectId()), needRelation: false });
317
+ }
318
+ async getPlugin(id) {
319
+ return this.post("/api_v2/gpt/ap/queryPlugin", { projectId: Number(await this.projectId()), pluginId: Number(id), convertStrategyV5: true });
320
+ }
321
+ async createPlugin(data3) {
322
+ return this.post("/api_v2/gpt/ap/createPlugin", { projectId: Number(await this.projectId()), ...data3 });
323
+ }
324
+ async updatePlugin(data3) {
325
+ return this.post("/api_v2/gpt/ap/updatePlugin", { projectId: Number(await this.projectId()), ...data3 });
326
+ }
327
+ async deletePlugin(id) {
328
+ return this.post("/api_v2/gpt/ap/deletePlugin", { projectId: Number(await this.projectId()), pluginId: Number(id) });
329
+ }
330
+ async runPlugin(config, requestBody) {
331
+ return this.post("/api_v2/gpt/ap/runHttpPlugin", {
332
+ projectId: Number(await this.projectId()),
333
+ botId: Number(await this.botId()),
334
+ externalHttpCallConfig: config,
335
+ ...requestBody === void 0 ? {} : { externalHttpCallRequestBody: requestBody }
336
+ });
337
+ }
338
+ async replaceMockData(type, records) {
339
+ if (records.length > 1e4) throw new Error("records must contain at most 10000 items");
340
+ return this.post(`/api_v2/gpt/mockdata/reAddMockData/${this.safePathSegment(type, "mock type")}`, records);
341
+ }
342
+ async queryMockData(type) {
343
+ return this.get("/api_v2/gpt/mockdata/queryMockData", { type: this.safePathSegment(type, "mock type"), globalData: false });
344
+ }
345
+ async listAiFields() {
346
+ return this.post("/api_v2/gpt/chatflow/queryAiFields", {});
347
+ }
348
+ async listAgentAiFields() {
349
+ return this.post("/api_v2/gpt/field/list/range", { fieldRange: ["all", "agent", "agent_preload_visible"] });
350
+ }
351
+ async aiFieldGuide() {
352
+ return this.post("/api_v2/tars/api/field/manage/guide/record", {});
353
+ }
354
+ async initializeAiFields() {
355
+ return this.get("/api_v2/tars/api/field/manage/pre/install");
356
+ }
357
+ async listManagedAiFields(pageIndex, pageSize2, name) {
358
+ return this.post("/api_v2/tars/api/field/manage/page", { pageIndex, pageSize: pageSize2, name });
359
+ }
360
+ async getManagedAiField(id) {
361
+ return this.get(`/api_v2/tars/api/field/manage/detail/${encodeURIComponent(id)}`);
362
+ }
363
+ async createManagedAiField(data3) {
364
+ return this.post("/api_v2/tars/api/field/manage/create", data3);
365
+ }
366
+ async updateManagedAiField(data3) {
367
+ return this.post("/api_v2/tars/api/field/manage/update", data3);
368
+ }
369
+ async deleteManagedAiField(id) {
370
+ return this.get(`/api_v2/tars/api/field/manage/delete/${encodeURIComponent(id)}`);
371
+ }
372
+ async toggleManagedAiField(id) {
373
+ return this.get(`/api_v2/tars/api/field/manage/switch/${encodeURIComponent(id)}`);
374
+ }
375
+ async chat(data3) {
376
+ const bot = String(data3.botId ?? await this.botId());
377
+ return this.post(`/api_v2/gpt/bot/${bot}/chat`, { botId: Number(bot), projectId: Number(await this.projectId()), option: { debug: true }, ...data3 });
378
+ }
379
+ async chatAsync(data3) {
380
+ const bot = String(data3.botId ?? await this.botId());
381
+ return this.post(`/api_v2/gpt/bot/${bot}/chat/async`, { botId: Number(bot), projectId: Number(await this.projectId()), option: { debug: true }, ...data3 });
382
+ }
383
+ async asyncResult(receipt, botId) {
384
+ const bot = botId ?? await this.botId();
385
+ return this.get(`/api_v2/gpt/bot/${bot}/chat/async/${encodeURIComponent(receipt)}`);
386
+ }
387
+ async listIntents(category = "E_COMMERCE") {
388
+ return this.get(`/api_v2/gpt/project/${await this.projectId()}/intents`, category ? { category } : void 0);
389
+ }
390
+ async getIntent(id) {
391
+ return this.get(`/api_v2/gpt/project/${await this.projectId()}/intent/${encodeURIComponent(id)}`);
392
+ }
393
+ async createIntent(data3) {
394
+ return this.post(`/api_v2/gpt/project/${await this.projectId()}/intent`, data3);
395
+ }
396
+ async updateIntent(id, data3) {
397
+ return this.put(`/api_v2/gpt/project/${await this.projectId()}/intent/${encodeURIComponent(id)}`, data3);
398
+ }
399
+ async toggleIntent(id, enabled2) {
400
+ return this.put(`/api_v2/gpt/project/${await this.projectId()}/intent/${encodeURIComponent(id)}/status`, { status: enabled2 ? "ENABLED" : "DISABLED" });
401
+ }
402
+ async listEntities() {
403
+ return this.get(`/api_v2/gpt/project/${await this.projectId()}/entities`);
404
+ }
405
+ async listStrategies(pageSize2 = 100) {
406
+ return this.get(`/api_v2/gpt/project/${await this.projectId()}/strategies`, { pageSize: pageSize2, pageNum: 1 });
407
+ }
408
+ async createStrategy(data3) {
409
+ return this.post(`/api_v2/gpt/project/${await this.projectId()}/strategy?v4=true`, data3);
410
+ }
411
+ async updateStrategy(id, data3) {
412
+ return this.request("PUT", `/api_v2/gpt/project/${await this.projectId()}/strategy/${encodeURIComponent(id)}`, data3);
413
+ }
414
+ async toggleStrategy(id, enabled2) {
415
+ return this.request("PUT", `/api_v2/gpt/project/${await this.projectId()}/strategy/${encodeURIComponent(id)}/status`, { status: enabled2 ? "ENABLED" : "DISABLED" });
416
+ }
417
+ async qualityStatus() {
418
+ return this.get("/api_v2/intelli/inspection/ticket/status");
419
+ }
420
+ async setQualityStatus(enabled2) {
421
+ return this.post("/api_v2/intelli/inspection/ticket/open", { open: enabled2, projectId: Number(await this.projectId()) });
422
+ }
423
+ async qualityRules(beginTimestamp, endTimestamp) {
424
+ return this.get("/api_v2/intelli/inspection/ticket/rules", { ...beginTimestamp === void 0 ? {} : { beginTimestamp }, ...endTimestamp === void 0 ? {} : { endTimestamp } });
425
+ }
426
+ async qualityRule(key) {
427
+ return this.get("/api_v2/intelli/inspection/ticket/rules/detail", { inspectionKey: key });
428
+ }
429
+ async updateQualityRule(data3) {
430
+ return this.post("/api_v2/intelli/inspection/ticket/rules", data3);
431
+ }
432
+ async customQualityRule(key) {
433
+ return this.post("/api_v2/intelli/inspection/ticket/customRules/detail", { inspectionKey: key });
434
+ }
435
+ async createCustomQualityRule(data3) {
436
+ return this.post("/api_v2/intelli/inspection/ticket/customRules/create", data3);
437
+ }
438
+ async updateCustomQualityRule(data3) {
439
+ return this.post("/api_v2/intelli/inspection/ticket/customRules/update", data3);
440
+ }
441
+ async deleteCustomQualityRule(key) {
442
+ return this.post("/api_v2/intelli/inspection/ticket/customRules/delete", { inspectionKey: key });
443
+ }
444
+ async listQualityAlertRules() {
445
+ return this.get("/api_v2/intelli/inspection/alert/list");
446
+ }
447
+ async getQualityAlertRule(id) {
448
+ return this.get("/api_v2/intelli/inspection/alert/detail", { id });
449
+ }
450
+ async createQualityAlertRule(data3) {
451
+ return this.post("/api_v2/intelli/inspection/alert/create", data3);
452
+ }
453
+ async updateQualityAlertRule(data3) {
454
+ return this.post("/api_v2/intelli/inspection/alert/update", data3);
455
+ }
456
+ async deleteQualityAlertRule(id) {
457
+ return this.get("/api_v2/intelli/inspection/alert/delete", { id });
458
+ }
459
+ async listQualityAlertMessages(data3) {
460
+ return this.post("/api_v2/intelli/inspection/alert/message/list", data3);
461
+ }
462
+ async getQualityAlertMessage(id) {
463
+ return this.get("/api_v2/intelli/inspection/alert/message/detail", { id });
464
+ }
465
+ async listTemplates(data3) {
466
+ return this.post(`/api_v2/gpt/project/${await this.projectId()}/templates/filter`, data3);
467
+ }
468
+ async createTemplate(data3) {
469
+ const content = String(data3.content ?? "");
470
+ return this.post(`/api_v2/gpt/project/${await this.projectId()}/template`, {
471
+ name: data3.name,
472
+ content,
473
+ status: data3.status ?? "ENABLED",
474
+ multiContent: data3.multiContent ?? { AUTO: content },
475
+ ...data3.scene ? { scene: data3.scene } : {}
476
+ });
477
+ }
478
+ async updateTemplate(id, data3) {
479
+ return this.put(`/api_v2/gpt/project/${await this.projectId()}/template/${encodeURIComponent(id)}`, data3);
480
+ }
481
+ async deleteTemplates(ids) {
482
+ return this.request("DELETE", `/api_v2/gpt/project/${await this.projectId()}/templates`, { templateIds: ids });
483
+ }
484
+ get qamPrefix() {
485
+ return this.env === "prod" ? "/api_v2/qam" : "/sns_v1";
486
+ }
487
+ get qamPath() {
488
+ return this.qamPrefix;
489
+ }
490
+ async listKnowledge(data3) {
491
+ return this.post(`${this.qamPrefix}/project/${await this.projectId()}/getKnowledge`, { type: "ALL", pageIndex: 1, pageSize: 50, keyword: "", ...data3 });
492
+ }
493
+ async getKnowledge(id) {
494
+ return this.get(`${this.qamPrefix}/project/${await this.projectId()}/ku/${encodeURIComponent(id)}`);
495
+ }
496
+ async updateKnowledge(id, data3) {
497
+ return this.request("PUT", `${this.qamPrefix}/project/${await this.projectId()}/ku`, { ...data3, kuId: Number(id) });
498
+ }
499
+ async uploadQa(items) {
500
+ return this.post(`${this.qamPrefix}/project/${await this.projectId()}/kus`, items);
501
+ }
502
+ async listDirectories() {
503
+ return this.get(`${this.qamPrefix}/project/${await this.projectId()}/directories`, { keyword: "", kuPublished: "" });
504
+ }
505
+ async createFolder(name, parentId = 0) {
506
+ return this.post(`${this.qamPrefix}/project/${await this.projectId()}/directory`, { name, parentId, type: "GENERIC" });
507
+ }
508
+ async updateDirectory(id, data3) {
509
+ return this.request("PUT", `${this.qamPrefix}/project/${await this.projectId()}/directory/${encodeURIComponent(id)}`, data3);
510
+ }
511
+ async deleteDirectory(id) {
512
+ return this.request("DELETE", `${this.qamPrefix}/project/${await this.projectId()}/directory/${encodeURIComponent(id)}`);
513
+ }
514
+ async knowledgeTags(keyword = "") {
515
+ return this.get(`${this.qamPrefix}/project/${await this.projectId()}/searchKeywordAndIntents`, { keyword });
516
+ }
517
+ async transcript(chatId) {
518
+ return this.get(`/api_v2/gpt/project/${await this.projectId()}/transcript/${encodeURIComponent(chatId)}`, { isCompare: true });
519
+ }
520
+ async listTranscripts(data3) {
521
+ return this.post(`/api_v2/gpt/project/${await this.projectId()}/transcripts/filter`, data3);
522
+ }
523
+ async resolveTranscriptChatId(externalId, pageSize2 = 10) {
524
+ const result = await this.listTranscripts({ pageSize: pageSize2, pageIndex: 1, debug: false, keyword: externalId });
525
+ const rows = Array.isArray(result) ? result : result?.list;
526
+ const items = Array.isArray(rows) ? rows.filter((row) => row && typeof row === "object") : [];
527
+ const exact = items.filter((row) => String(row.externId ?? row.externalId ?? row.external_id ?? "") === externalId);
528
+ const matches = (exact.length ? exact : items).map((row) => ({ chatId: row.chatId ?? row.id, externalId: row.externId ?? row.externalId ?? row.external_id, agentName: row.agentName ?? "", touchPoint: row.touchPoint ?? row.touchpoint ?? "", createdAt: row.createdAt ?? "" }));
529
+ return { externalId, chatId: exact.length || matches.length === 1 ? matches[0]?.chatId ?? null : null, matchedBy: exact.length ? "exactExternalId" : "keyword", matches };
530
+ }
531
+ async chatContext(botId, data3) {
532
+ return this.post(`/api_v2/gpt/bot/${encodeURIComponent(botId)}/chat/context/compare`, data3);
533
+ }
534
+ };
535
+
536
+ // src/solvea/input.ts
537
+ import { readFile } from "fs/promises";
538
+ async function jsonData(args, required = true) {
539
+ const file = option(args, "--data-file");
540
+ const raw = file ? await readFile(file, "utf8") : option(args, "--data");
541
+ if (!raw) {
542
+ if (required) throw new Error("--data or --data-file is required");
543
+ return {};
544
+ }
545
+ const parsed = JSON.parse(raw);
546
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("request data must be a JSON object");
547
+ return parsed;
548
+ }
549
+ async function jsonValue(args) {
550
+ const file = option(args, "--data-file");
551
+ const raw = file ? await readFile(file, "utf8") : option(args, "--data", true);
552
+ return JSON.parse(raw);
553
+ }
554
+ function requireFlag(args, name, command) {
555
+ if (!flag(args, name)) throw new Error(`${command} requires ${name} after explicit user acknowledgement`);
556
+ }
557
+ function requireId(args) {
558
+ return option(args, "--id", true);
559
+ }
560
+
561
+ // src/solvea/extended-commands.ts
562
+ var handlers = {
563
+ "replace-mock-data": async (client, args) => {
564
+ const records = await jsonValue(args);
565
+ if (!Array.isArray(records)) throw new Error("replace-mock-data requires a JSON array");
566
+ return client.replaceMockData(option(args, "--name", true), records);
567
+ },
568
+ "query-mock-data": (client, args) => client.queryMockData(option(args, "--name", true)),
569
+ "run-plugin": async (client, args) => {
570
+ const payload = await jsonData(args);
571
+ const config = "externalHttpCallConfig" in payload ? payload.externalHttpCallConfig : payload;
572
+ return client.runPlugin(config, payload.externalHttpCallRequestBody);
573
+ },
574
+ "list-ai-fields": (client) => client.listAiFields(),
575
+ "list-agent-ai-fields": (client) => client.listAgentAiFields(),
576
+ "get-ai-field-guide": (client) => client.aiFieldGuide(),
577
+ "initialize-ai-fields": (client) => client.initializeAiFields(),
578
+ "list-managed-ai-fields": (client, args) => client.listManagedAiFields(
579
+ Number(option(args, "--page") ?? 1),
580
+ Number(option(args, "--page-size") ?? 50),
581
+ option(args, "--keyword") ?? ""
582
+ ),
583
+ "get-managed-ai-field": (client, args) => client.getManagedAiField(requireId(args)),
584
+ "create-managed-ai-field": async (client, args) => client.createManagedAiField(await jsonData(args)),
585
+ "update-managed-ai-field": async (client, args) => client.updateManagedAiField(await jsonData(args)),
586
+ "delete-managed-ai-field": async (client, args) => {
587
+ requireFlag(args, "--confirm-delete", "delete-managed-ai-field");
588
+ return client.deleteManagedAiField(requireId(args));
589
+ },
590
+ "toggle-managed-ai-field": (client, args) => client.toggleManagedAiField(requireId(args)),
591
+ "list-quality-alert-rules": (client) => client.listQualityAlertRules(),
592
+ "get-quality-alert-rule": (client, args) => client.getQualityAlertRule(requireId(args)),
593
+ "create-quality-alert-rule": async (client, args) => client.createQualityAlertRule(await jsonData(args)),
594
+ "update-quality-alert-rule": async (client, args) => client.updateQualityAlertRule(await jsonData(args)),
595
+ "delete-quality-alert-rule": async (client, args) => {
596
+ requireFlag(args, "--confirm-delete", "delete-quality-alert-rule");
597
+ return client.deleteQualityAlertRule(requireId(args));
598
+ },
599
+ "list-quality-alert-messages": async (client, args) => client.listQualityAlertMessages(await jsonData(args)),
600
+ "get-quality-alert-message": (client, args) => client.getQualityAlertMessage(requireId(args)),
601
+ "list-templates": (client, args) => client.listTemplates({
602
+ pageIndex: Number(option(args, "--page") ?? 1),
603
+ pagesize: Number(option(args, "--page-size") ?? 50),
604
+ keyword: option(args, "--keyword") ?? "",
605
+ ...options2(args, "--scene").length ? { scenes: options2(args, "--scene") } : {},
606
+ ...option(args, "--status") ? { status: [option(args, "--status")] } : {}
607
+ }),
608
+ "create-template": async (client, args) => {
609
+ const payload = await jsonData(args, false);
610
+ if (option(args, "--name")) payload.name = option(args, "--name");
611
+ if (option(args, "--content")) payload.content = option(args, "--content");
612
+ if (option(args, "--status")) payload.status = option(args, "--status");
613
+ if (options2(args, "--scene")[0]) payload.scene = options2(args, "--scene")[0];
614
+ if (!payload.name || !payload.content) throw new Error("create-template requires name and content");
615
+ return client.createTemplate(payload);
616
+ },
617
+ "update-template": async (client, args) => {
618
+ const payload = await jsonData(args, false);
619
+ for (const [field, name] of [["name", "--name"], ["content", "--content"], ["status", "--status"]]) {
620
+ if (option(args, name)) payload[field] = option(args, name);
621
+ }
622
+ if (!Object.keys(payload).length) throw new Error("update-template requires at least one changed field");
623
+ return client.updateTemplate(requireId(args), payload);
624
+ },
625
+ "delete-templates": async (client, args) => {
626
+ requireFlag(args, "--confirm-delete", "delete-templates");
627
+ const ids = optionList(args, "--ids").map(Number);
628
+ if (!ids.length || ids.some((id) => !Number.isSafeInteger(id) || id <= 0)) throw new Error("delete-templates requires positive integer --ids");
629
+ return client.deleteTemplates(ids);
630
+ }
631
+ };
632
+ var EXTENDED_COMMANDS = new Set(Object.keys(handlers));
633
+ async function runExtendedCommand(client, command, args) {
634
+ const handler = handlers[command];
635
+ if (!handler) throw new Error(`TypeScript command not migrated yet: ${command}`);
636
+ return handler(client, args);
637
+ }
638
+
639
+ // src/solvea/remaining-commands.ts
640
+ var data = async (args) => jsonData(args, false);
641
+ var project = async (client) => client.projectId();
642
+ var page = (args) => Number(option(args, "--page") ?? 1);
643
+ var pageSize = (args) => Number(option(args, "--page-size") ?? 50);
644
+ var reportBody = async (args) => ({
645
+ beginTimestamp: Number(option(args, "--begin-ts", true)),
646
+ endTimestamp: Number(option(args, "--end-ts", true)),
647
+ timeOffset: Number(option(args, "--time-offset") ?? 8),
648
+ ...await data(args)
649
+ });
650
+ var handlers2 = {
651
+ "chat-stream": async (c, a) => c.rawCall("POST", `/api_v2/gpt/bot/${await c.botId()}/chat`, { message: option(a, "--message", true), botId: Number(option(a, "--bot-id") ?? await c.botId()), projectId: Number(await project(c)), option: { debug: true }, stream: true }),
652
+ "update-chatflow": async (c, a) => c.updateChatflow(option(a, "--agent-id", true), await jsonData(a), flag(a, "--publish")),
653
+ "get-conversations-by-intent": async (c, a) => c.listTranscripts({ pageSize: Number(option(a, "--limit") ?? 50), pageIndex: 1, intent: option(a, "--intent", true) }),
654
+ "resolve-transcript-chat-id": async (c, a) => c.resolveTranscriptChatId(option(a, "--external-id", true), Number(option(a, "--page-size") ?? 10)),
655
+ "list-isolation-keywords": async (c, a) => c.rawCall("GET", `${c.qamPath}/project/${await project(c)}/isolation_keywords`, void 0, { keyword: option(a, "--keyword") ?? "", pageIndex: page(a), pageSize: pageSize(a) }),
656
+ "create-isolation-keyword": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/isolation_keyword`, { keyword: option(a, "--keyword", true) }),
657
+ "update-isolation-keyword": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/isolation_keyword/${requireId(a)}`, { keyword: option(a, "--keyword", true) }),
658
+ "delete-isolation-keyword": async (c, a) => {
659
+ requireFlag(a, "--confirm-delete", "delete-isolation-keyword");
660
+ return c.rawCall("DELETE", `${c.qamPath}/project/${await project(c)}/isolation_keyword/${requireId(a)}`);
661
+ },
662
+ "get-knowledge-isolation-keywords": async (c, a) => c.rawCall("GET", `${c.qamPath}/project/${await project(c)}/knowledge/isolation_keywords`, void 0, { knowledgeType: option(a, "--type", true), knowledgeId: requireId(a) }),
663
+ "batch-update-isolation-keyword-bindings": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/knowledge/isolation_keywords/batch`, await jsonValue(a)),
664
+ "edit-knowledge-tags": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/editTags`, await jsonValue(a)),
665
+ "move-directory": async (c, a) => c.rawCall("GET", `${c.qamPath}/project/${await project(c)}/directory/move`, void 0, { currentId: requireId(a), parentId: option(a, "--parent-id", true) }),
666
+ "operate-knowledge": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/updateKnowledge`, await jsonValue(a)),
667
+ "batch-update-knowledge": async (c, a) => c.rawCall("PUT", `${c.qamPath}/project/${await project(c)}/kus`, await jsonValue(a)),
668
+ "update-document-content": async (c, a) => c.rawCall("PUT", `${c.qamPath}/project/${await project(c)}/document`, { id: requireId(a), ...await data(a) }),
669
+ "create-product-knowledge": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/ku_product`, await jsonValue(a)),
670
+ "update-product-knowledge": async (c, a) => c.rawCall("PUT", `${c.qamPath}/project/${await project(c)}/ku_product`, { kuProductId: Number(requireId(a)), ...await data(a) }),
671
+ "batch-update-products": async (c, a) => c.rawCall("PUT", `${c.qamPath}/project/${await project(c)}/ku_products`, { list: await jsonValue(a) }),
672
+ "upload-web": async (c, a) => c.rawCall("POST", `${c.qamPath}/project/${await project(c)}/documents`, { documents: optionList(a, "--url").map((filePath) => ({ filePath, docType: "TC", fileType: "website" })), taskType: "WEB", published: true, isVisible: true, metadata: { tags: [] }, directoryId: option(a, "--directory-id") ?? "" }),
673
+ "list-label-groups": async (c, a) => c.rawCall("GET", `/api_v2/gpt/label/project/${await project(c)}/getTreeInfo`, void 0, option(a, "--name") ? { treeName: option(a, "--name") } : void 0),
674
+ "create-label-group": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateTreeInfo`, { ...await data(a), treeName: option(a, "--name", true), operateType: "CREATE" }),
675
+ "update-label-group": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateTreeInfo`, { ...await data(a), id: Number(requireId(a)), operateType: "UPDATE" }),
676
+ "delete-label-group": async (c, a) => {
677
+ requireFlag(a, "--confirm-delete", "delete-label-group");
678
+ return c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateTreeInfo`, { id: Number(requireId(a)), operateType: "DELETE" });
679
+ },
680
+ "get-label-tree": async (c, a) => c.rawCall("GET", `/api_v2/gpt/label/project/${await project(c)}/getTagTree`, void 0, { treeId: requireId(a), ...option(a, "--keyword") ? { name: option(a, "--keyword") } : {} }),
681
+ "get-label-detail-tree": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/getDetailTree`, { treeId: Number(requireId(a)), ...await data(a) }),
682
+ "create-label-node": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateNode`, { treeId: Number(option(a, "--tree-id", true)), operateType: "CREATE", nodes: [await data(a)] }),
683
+ "update-label-node": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateNode`, { treeId: Number(option(a, "--tree-id", true)), operateType: "UPDATE", nodes: [{ id: Number(requireId(a)), ...await data(a) }] }),
684
+ "delete-label-node": async (c, a) => {
685
+ requireFlag(a, "--confirm-delete", "delete-label-node");
686
+ return c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/updateNode`, { treeId: Number(option(a, "--tree-id", true)), operateType: "DELETE", nodes: [{ id: Number(requireId(a)) }] });
687
+ },
688
+ "download-label-template": async (c, a) => c.rawCall("GET", `/api_v2/gpt/label/project/${await project(c)}/downloadLabelTemplate`, void 0, { type: option(a, "--template-type") ?? "VOC_LABEL" }),
689
+ "download-labels": async (c, a) => c.rawCall("GET", `/api_v2/gpt/label/project/${await project(c)}/downloadLabel`, void 0, { treeId: option(a, "--tree-id", true) }),
690
+ "upload-labels": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/uploadLabel`, { treeId: Number(option(a, "--tree-id", true)), file: option(a, "--file", true), ...option(a, "--init") ? { uploadWay: "INIT" } : {} }),
691
+ "export-transcripts": async (c, a) => c.rawCall("POST", `/api_v2/gpt/project/${await project(c)}/transcripts/export/async`, { pageSize: pageSize(a), pageIndex: page(a), timeOffset: Number(option(a, "--time-offset") ?? 8), ...await data(a) }),
692
+ "get-export-tasks": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/getLabelTask`, { page: page(a), pageSize: pageSize(a) }),
693
+ "upload-batch-test-file": async (c, a) => c.rawCall("GET", `/api_v2/gpt/project/${await project(c)}/sts_credentials`),
694
+ "submit-batch-test": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/uploadMessage`, { file: option(a, "--file", true), type: option(a, "--type", true), ...option(a, "--bot-id") ? { botId: Number(option(a, "--bot-id")) } : {}, ...await data(a) }),
695
+ "get-batch-test-tasks": async (c, a) => c.rawCall("POST", `/api_v2/gpt/label/project/${await project(c)}/getLabelTask`, { page: page(a), pageSize: pageSize(a), ...option(a, "--type") ? { taskType: option(a, "--type") } : {} }),
696
+ "list-voice-agents": (c) => c.listAgents("voice"),
697
+ "list-voice-transcripts": async (c, a) => c.rawCall("POST", "/api_v2/as_bot/voice-report/transcript-page", { pageNum: page(a), pageSize: pageSize(a), beginTimestamp: Number(option(a, "--begin-ts") ?? 0), endTimestamp: Number(option(a, "--end-ts") ?? 0) }),
698
+ "get-voice-transcript": async (c, a) => c.rawCall("GET", `/api_v2/gpt/voice/transcript/projectId/${await project(c)}/history/${requireId(a)}`)
699
+ };
700
+ var reportPaths = {
701
+ "report-transcript": "/api_v2/as_bot/statement/transcript",
702
+ "report-message": "/api_v2/as_bot/statement/message",
703
+ "report-agent": "/api_v2/as_bot/statement/agent",
704
+ "report-intent": "/api_v2/as_bot/statement/transcript/intent",
705
+ "report-satisfaction": "/api_v2/as_bot/statement/satisfaction/feedback",
706
+ "report-satisfaction-list": "/api_v2/as_bot/statement/satisfaction/message",
707
+ "report-knowledge": "/api_v2/as_bot/statement/knowledge",
708
+ "report-escalation": "/api_v2/as_bot/statement/transcript/reason2",
709
+ "report-livechat": "/api_v2/as_bot/livechat/report/summary",
710
+ "report-livechat-table": "/api_v2/as_bot/livechat/report/table",
711
+ "report-inspection": "/api_v2/intelli/inspection/ticket/count",
712
+ "report-self-learning": "/api_v2/as_bot/statement/self-learning"
713
+ };
714
+ for (const [name, path] of Object.entries(reportPaths)) handlers2[name] = async (c, a) => c.rawCall("POST", path, await reportBody(a));
715
+ var REMAINING_COMMANDS = new Set(Object.keys(handlers2));
716
+ async function runRemainingCommand(client, command, args) {
717
+ const handler = handlers2[command];
718
+ if (!handler) throw new Error(`TypeScript command not migrated yet: ${command}`);
719
+ return handler(client, args);
720
+ }
721
+
722
+ // src/solvea/commands.ts
723
+ function requireFlag2(args, name, command) {
724
+ if (!flag(args, name)) throw new Error(`${command} requires ${name} after explicit user acknowledgement`);
725
+ }
726
+ function enabled(args, command) {
727
+ const enable = flag(args, "--enable");
728
+ const disable = flag(args, "--disable");
729
+ if (enable === disable) throw new Error(`${command} requires exactly one of --enable or --disable`);
730
+ return enable;
731
+ }
732
+ async function data2(args) {
733
+ const file = option(args, "--data-file");
734
+ const raw = file ? await readFile2(file, "utf8") : option(args, "--data");
735
+ if (!raw) throw new Error("--data or --data-file is required");
736
+ const parsed = JSON.parse(raw);
737
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("request data must be a JSON object");
738
+ return parsed;
739
+ }
740
+ async function transcriptFilters(args) {
741
+ const filters = {
742
+ pageIndex: Number(option(args, "--page") ?? 1),
743
+ pageSize: Number(option(args, "--page-size") ?? 50),
744
+ debug: flag(args, "--debug"),
745
+ ...await optionalData(args)
746
+ };
747
+ const optional = [
748
+ ["beginTimestamp", "--begin-ts", Number],
749
+ ["endTimestamp", "--end-ts", Number],
750
+ ["touchPoint", "--touch-point", String],
751
+ ["botId", "--bot-id", Number],
752
+ ["agentId", "--agent-id", Number],
753
+ ["intentId", "--intent-id", Number],
754
+ ["keyword", "--keyword", String],
755
+ ["handoff", "--handoff", (value) => value === "true"]
756
+ ];
757
+ for (const [field, name, convert] of optional) {
758
+ const value = option(args, name);
759
+ if (value !== void 0) filters[field] = convert(value);
760
+ }
761
+ return filters;
762
+ }
763
+ async function runSolveaCommand(session, command, args) {
764
+ const client = new SolveaClient(session);
765
+ if (EXTENDED_COMMANDS.has(command)) return runExtendedCommand(client, command, args);
766
+ if (REMAINING_COMMANDS.has(command)) return runRemainingCommand(client, command, args);
767
+ if (command.startsWith("chat-report-")) return runRemainingCommand(client, "report-message", args);
768
+ const id = () => option(args, "--id", true);
769
+ switch (command) {
770
+ case "get-project":
771
+ return client.projectInfo();
772
+ case "list-agents":
773
+ return client.listAgents(option(args, "--category") ?? "text");
774
+ case "get-agent":
775
+ return client.getAgent(id());
776
+ case "get-chatflow-graph":
777
+ return client.getChatflowGraph(option(args, "--agent-id", true));
778
+ case "create-agent":
779
+ return client.createAgent(await data2(args));
780
+ case "update-agent":
781
+ return client.updateAgent(await data2(args));
782
+ case "list-plugins":
783
+ return client.listPlugins();
784
+ case "get-plugin":
785
+ return client.getPlugin(id());
786
+ case "create-plugin":
787
+ return client.createPlugin(await data2(args));
788
+ case "update-plugin":
789
+ return client.updatePlugin(await data2(args));
790
+ case "delete-plugin":
791
+ requireFlag2(args, "--confirm-delete", command);
792
+ return client.deletePlugin(id());
793
+ case "chat":
794
+ return client.chat({ message: option(args, "--message") ?? option(args, "-m", true), botId: option(args, "--bot-id"), chatId: option(args, "--chat-id"), touchPoint: option(args, "--touch-point") ?? "LIVE_CHAT", ...await optionalData(args) });
795
+ case "chat-async":
796
+ return client.chatAsync({ message: option(args, "--message") ?? option(args, "-m", true), botId: option(args, "--bot-id"), chatId: option(args, "--chat-id"), touchPoint: option(args, "--touch-point") ?? "LIVE_CHAT", ...await optionalData(args) });
797
+ case "get-async-result":
798
+ return client.asyncResult(option(args, "--receipt", true), option(args, "--bot-id"));
799
+ case "list-intents":
800
+ return client.listIntents(option(args, "--category") ?? "E_COMMERCE");
801
+ case "get-intent":
802
+ return client.getIntent(id());
803
+ case "create-intent":
804
+ return client.createIntent(await data2(args));
805
+ case "update-intent":
806
+ return client.updateIntent(id(), await data2(args));
807
+ case "toggle-intent":
808
+ return client.toggleIntent(id(), !flag(args, "--disable"));
809
+ case "list-entities":
810
+ return client.listEntities();
811
+ case "list-strategies":
812
+ return client.listStrategies(Number(option(args, "--page-size") ?? 100));
813
+ case "create-strategy":
814
+ return client.createStrategy(await data2(args));
815
+ case "update-strategy":
816
+ return client.updateStrategy(id(), await data2(args));
817
+ case "toggle-strategy":
818
+ return client.toggleStrategy(id(), !flag(args, "--disable"));
819
+ case "get-quality-status":
820
+ return client.qualityStatus();
821
+ case "set-quality-status":
822
+ return client.setQualityStatus(enabled(args, command));
823
+ case "list-quality-rules":
824
+ return client.qualityRules(Number(option(args, "--begin-ts") ?? 0) || void 0, Number(option(args, "--end-ts") ?? 0) || void 0);
825
+ case "get-quality-rule":
826
+ return client.qualityRule(option(args, "--inspection-key", true));
827
+ case "update-quality-rule":
828
+ return client.updateQualityRule(await data2(args));
829
+ case "get-custom-quality-rule":
830
+ return client.customQualityRule(option(args, "--inspection-key", true));
831
+ case "create-custom-quality-rule":
832
+ return client.createCustomQualityRule(await data2(args));
833
+ case "update-custom-quality-rule":
834
+ return client.updateCustomQualityRule(await data2(args));
835
+ case "delete-custom-quality-rule":
836
+ return client.deleteCustomQualityRule(option(args, "--inspection-key", true));
837
+ case "list-knowledge":
838
+ return client.listKnowledge(await optionalData(args));
839
+ case "get-knowledge":
840
+ return client.getKnowledge(id());
841
+ case "update-knowledge":
842
+ return client.updateKnowledge(id(), await data2(args));
843
+ case "upload-qa":
844
+ return client.uploadQa((await data2(args)).items);
845
+ case "list-directories":
846
+ return client.listDirectories();
847
+ case "create-folder":
848
+ return client.createFolder(option(args, "--name", true), Number(option(args, "--parent-id") ?? 0));
849
+ case "update-directory":
850
+ return client.updateDirectory(id(), option(args, "--name") ? { name: option(args, "--name") } : await data2(args));
851
+ case "delete-directory":
852
+ requireFlag2(args, "--confirm-delete", command);
853
+ return client.deleteDirectory(id());
854
+ case "list-knowledge-tags":
855
+ return client.knowledgeTags(option(args, "--keyword") ?? "");
856
+ case "get-transcript":
857
+ return client.transcript(option(args, "--chat-id", true));
858
+ case "list-transcripts":
859
+ return client.listTranscripts(await transcriptFilters(args));
860
+ case "get-chat-context":
861
+ return client.chatContext(option(args, "--bot-id", true), await data2(args));
862
+ default:
863
+ throw new Error(`TypeScript command not migrated yet: ${command}`);
864
+ }
865
+ }
866
+ async function optionalData(args) {
867
+ if (!option(args, "--data") && !option(args, "--data-file")) return {};
868
+ return data2(args);
192
869
  }
870
+ function isNativeSolveaCommand(command) {
871
+ return command.startsWith("chat-report-") || EXTENDED_COMMANDS.has(command) || REMAINING_COMMANDS.has(command) || (/* @__PURE__ */ new Set([
872
+ "get-project",
873
+ "list-agents",
874
+ "get-agent",
875
+ "get-chatflow-graph",
876
+ "create-agent",
877
+ "update-agent",
878
+ "list-plugins",
879
+ "get-plugin",
880
+ "create-plugin",
881
+ "update-plugin",
882
+ "delete-plugin",
883
+ "chat",
884
+ "chat-async",
885
+ "get-async-result",
886
+ "list-intents",
887
+ "get-intent",
888
+ "create-intent",
889
+ "update-intent",
890
+ "toggle-intent",
891
+ "list-entities",
892
+ "list-strategies",
893
+ "create-strategy",
894
+ "update-strategy",
895
+ "toggle-strategy",
896
+ "get-transcript",
897
+ "list-transcripts",
898
+ "get-chat-context",
899
+ "get-quality-status",
900
+ "set-quality-status",
901
+ "list-quality-rules",
902
+ "get-quality-rule",
903
+ "update-quality-rule",
904
+ "get-custom-quality-rule",
905
+ "create-custom-quality-rule",
906
+ "update-custom-quality-rule",
907
+ "delete-custom-quality-rule",
908
+ "list-knowledge",
909
+ "get-knowledge",
910
+ "update-knowledge",
911
+ "upload-qa",
912
+ "list-directories",
913
+ "create-folder",
914
+ "update-directory",
915
+ "delete-directory",
916
+ "list-knowledge-tags"
917
+ ])).has(command);
918
+ }
919
+
920
+ // src/business.ts
921
+ var packageRoot = () => resolve(dirname(fileURLToPath(import.meta.url)), "..");
193
922
  async function runApi(session, command, args) {
194
- const code = await runPython("skills/__lib__/solvea-api/solvea_api.py", [command, ...args], session);
195
- if (code) throw new Error(`business command ${command} failed with exit code ${code}`);
923
+ if (isNativeSolveaCommand(command)) {
924
+ console.log(JSON.stringify(await runSolveaCommand(session, command, args), null, 2));
925
+ return;
926
+ }
927
+ throw new Error(`unknown TypeScript API command: ${command}`);
928
+ }
929
+
930
+ // src/commands/resources.ts
931
+ var action = (command, summary, usage2 = "") => ({ command, summary, usage: usage2 });
932
+ var resources = {
933
+ agent: {
934
+ list: action("list-agents", "List agents", "[--category text|voice]"),
935
+ get: action("get-agent", "Get one agent", "--id <agent-id>"),
936
+ create: action("create-agent", "Create an agent", "--data <json> | --data-file <path>"),
937
+ update: action("update-agent", "Update an agent", "--data <json> | --data-file <path>"),
938
+ "get-chatflow": action("get-chatflow-graph", "Get an agent chatflow", "--agent-id <agent-id>")
939
+ },
940
+ intent: {
941
+ list: action("list-intents", "List intents", "[--category <category>]"),
942
+ get: action("get-intent", "Get one intent", "--id <intent-id>"),
943
+ create: action("create-intent", "Create an intent", "--data <json> | --data-file <path>"),
944
+ update: action("update-intent", "Update an intent", "--id <intent-id> (--data <json> | --data-file <path>)"),
945
+ toggle: action("toggle-intent", "Enable or disable an intent", "--id <intent-id> [--enable | --disable] (default: --enable)")
946
+ },
947
+ strategy: {
948
+ list: action("list-strategies", "List strategies", "[--page-size <number>]"),
949
+ entities: action("list-entities", "List strategy entities"),
950
+ create: action("create-strategy", "Create a strategy", "--data <json> | --data-file <path>"),
951
+ update: action("update-strategy", "Update a strategy", "--id <strategy-id> (--data <json> | --data-file <path>)"),
952
+ toggle: action("toggle-strategy", "Enable or disable a strategy", "--id <strategy-id> [--enable | --disable] (default: --enable)")
953
+ },
954
+ tool: {
955
+ list: action("list-plugins", "List tools"),
956
+ get: action("get-plugin", "Get one tool", "--id <tool-id>"),
957
+ create: action("create-plugin", "Create a tool", "--data <json> | --data-file <path>"),
958
+ update: action("update-plugin", "Update a tool", "--data <json> | --data-file <path>"),
959
+ delete: action("delete-plugin", "Delete a tool", "--id <tool-id> --confirm-delete"),
960
+ run: action("run-plugin", "Run an HTTP tool without saving it", "--data <json> | --data-file <path>")
961
+ },
962
+ field: {
963
+ canvas: action("list-ai-fields", "List CHAT_FLOW canvas fields"),
964
+ "agent-range": action("list-agent-ai-fields", "List fields accepted by Agent validation"),
965
+ guide: action("get-ai-field-guide", "Get AI Field initialization status"),
966
+ initialize: action("initialize-ai-fields", "Initialize system AI Fields"),
967
+ list: action("list-managed-ai-fields", "List managed AI Fields", "[--page <number>] [--page-size <number>] [--keyword <name>]"),
968
+ get: action("get-managed-ai-field", "Get one managed AI Field", "--id <field-id>"),
969
+ create: action("create-managed-ai-field", "Create a managed AI Field", "--data <json> | --data-file <path>"),
970
+ update: action("update-managed-ai-field", "Update a managed AI Field", "--data <json> | --data-file <path>"),
971
+ delete: action("delete-managed-ai-field", "Delete a managed AI Field", "--id <field-id> --confirm-delete"),
972
+ toggle: action("toggle-managed-ai-field", "Toggle a managed AI Field", "--id <field-id>")
973
+ },
974
+ template: {
975
+ list: action("list-templates", "List reply templates", "[--page <number>] [--page-size <number>] [--keyword <text>] [--scene <scene>] [--status <status>]"),
976
+ create: action("create-template", "Create a reply template", "(--name <name> --content <content>) | --data-file <path>"),
977
+ update: action("update-template", "Update a reply template", "--id <template-id> [--name <name>] [--content <content>] [--status <status>] [--data-file <path>]"),
978
+ delete: action("delete-templates", "Delete reply templates", "--ids <id> [id...] --confirm-delete")
979
+ },
980
+ knowledge: {
981
+ list: action("list-knowledge", "List knowledge", "[--data <json> | --data-file <path>]"),
982
+ get: action("get-knowledge", "Get one knowledge item", "--id <knowledge-id>"),
983
+ update: action("update-knowledge", "Update a knowledge item", "--id <knowledge-id> (--data <json> | --data-file <path>)"),
984
+ "upload-qa": action("upload-qa", "Upload QA items", "--data <json> | --data-file <path>"),
985
+ tags: action("list-knowledge-tags", "List knowledge tags", "[--keyword <keyword>]")
986
+ },
987
+ directory: {
988
+ list: action("list-directories", "List knowledge directories"),
989
+ create: action("create-folder", "Create a knowledge directory", "--name <name> [--parent-id <directory-id>]"),
990
+ update: action("update-directory", "Update a knowledge directory", "--id <directory-id> (--name <name> | --data <json> | --data-file <path>)"),
991
+ delete: action("delete-directory", "Delete a knowledge directory", "--id <directory-id> --confirm-delete")
992
+ },
993
+ quality: {
994
+ status: action("get-quality-status", "Get quality inspection status"),
995
+ toggle: action("set-quality-status", "Enable or disable quality inspection", "--enable | --disable"),
996
+ rules: action("list-quality-rules", "List quality rules", "[--begin-ts <milliseconds>] [--end-ts <milliseconds>]"),
997
+ "get-rule": action("get-quality-rule", "Get one quality rule", "--inspection-key <key>"),
998
+ "update-rule": action("update-quality-rule", "Update a quality rule", "--data <json> | --data-file <path>"),
999
+ "get-custom-rule": action("get-custom-quality-rule", "Get one custom quality rule", "--inspection-key <key>"),
1000
+ "create-custom-rule": action("create-custom-quality-rule", "Create a custom quality rule", "--data <json> | --data-file <path>"),
1001
+ "update-custom-rule": action("update-custom-quality-rule", "Update a custom quality rule", "--data <json> | --data-file <path>"),
1002
+ "delete-custom-rule": action("delete-custom-quality-rule", "Delete a custom quality rule", "--inspection-key <key>"),
1003
+ alerts: action("list-quality-alert-rules", "List quality alert rules"),
1004
+ "get-alert": action("get-quality-alert-rule", "Get one quality alert rule", "--id <alert-id>"),
1005
+ "create-alert": action("create-quality-alert-rule", "Create a quality alert rule", "--data <json> | --data-file <path>"),
1006
+ "update-alert": action("update-quality-alert-rule", "Update a quality alert rule", "--data <json> | --data-file <path>"),
1007
+ "delete-alert": action("delete-quality-alert-rule", "Delete a quality alert rule", "--id <alert-id> --confirm-delete"),
1008
+ "alert-messages": action("list-quality-alert-messages", "List quality alert messages", "--data <json> | --data-file <path>"),
1009
+ "get-alert-message": action("get-quality-alert-message", "Get one quality alert message", "--id <message-id>")
1010
+ },
1011
+ transcript: {
1012
+ list: action("list-transcripts", "List transcripts", "[--page <number>] [--page-size <number>] [--begin-ts <milliseconds>] [--end-ts <milliseconds>] [--data <json> | --data-file <path>]"),
1013
+ get: action("get-transcript", "Get one transcript", "--chat-id <chat-id>"),
1014
+ context: action("get-chat-context", "Get chat context", "--bot-id <bot-id> (--data <json> | --data-file <path>)")
1015
+ },
1016
+ chat: {
1017
+ send: action("chat", "Send a synchronous chat message", "--message <text> [--bot-id <bot-id>] [--chat-id <chat-id>]"),
1018
+ async: action("chat-async", "Send an asynchronous chat message", "--message <text> [--bot-id <bot-id>] [--chat-id <chat-id>]"),
1019
+ result: action("get-async-result", "Get an asynchronous chat result", "--receipt <receipt> [--bot-id <bot-id>]")
1020
+ }
1021
+ };
1022
+ function isResourceCommand(value) {
1023
+ return value in resources;
1024
+ }
1025
+ function resourceHelp(resource, actionName) {
1026
+ if (!resource) return `Business resources:
1027
+ ${Object.keys(resources).map((name) => ` ${name}`).join("\n")}`;
1028
+ if (!isResourceCommand(resource)) throw new Error(`unknown resource: ${resource}`);
1029
+ const actions = resources[resource];
1030
+ if (actionName) {
1031
+ const definition = actions[actionName];
1032
+ if (!definition) throw new Error(`unknown ${resource} action: ${actionName}
1033
+ ${resourceHelp(resource)}`);
1034
+ return [
1035
+ definition.summary,
1036
+ `Usage: cxclawctl ${resource} ${actionName}${definition.usage ? ` ${definition.usage}` : ""}`
1037
+ ].join("\n\n");
1038
+ }
1039
+ return [
1040
+ `${resource} actions:`,
1041
+ ...Object.entries(actions).map(([name, definition]) => ` ${name.padEnd(20)} ${definition.summary}`),
1042
+ `
1043
+ Run cxclawctl ${resource} <action> --help for action options.`
1044
+ ].join("\n");
1045
+ }
1046
+ function resolveResourceCommand(resource, action2) {
1047
+ if (!action2 || action2 === "help") throw new Error(resourceHelp(resource));
1048
+ const definition = resources[resource][action2];
1049
+ if (!definition) throw new Error(`unknown ${resource} action: ${action2}
1050
+ ${resourceHelp(resource)}`);
1051
+ return definition.command;
1052
+ }
1053
+ async function runResourceCommand(session, resource, action2, args) {
1054
+ await runApi(session, resolveResourceCommand(resource, action2), args);
1055
+ }
1056
+
1057
+ // src/doctor.ts
1058
+ import { access } from "fs/promises";
1059
+ import { join } from "path";
1060
+ async function diagnose() {
1061
+ const root2 = packageRoot();
1062
+ const requiredFiles = [
1063
+ "package.json"
1064
+ ];
1065
+ await Promise.all(requiredFiles.map((path) => access(join(root2, path))));
1066
+ const expectedPluginVersion = process.env.CXCLAW_PLUGIN_VERSION || null;
1067
+ if (expectedPluginVersion && expectedPluginVersion !== VERSION) {
1068
+ throw new Error(
1069
+ `plugin version ${expectedPluginVersion} does not match CLI ${VERSION}`
1070
+ );
1071
+ }
1072
+ return {
1073
+ ok: true,
1074
+ cliVersion: VERSION,
1075
+ pluginVersion: expectedPluginVersion,
1076
+ versionsMatch: expectedPluginVersion ? expectedPluginVersion === VERSION : null,
1077
+ nodeVersion: process.versions.node,
1078
+ runtimeFiles: requiredFiles
1079
+ };
196
1080
  }
197
1081
 
198
1082
  // src/sls.ts
199
1083
  import LogClient from "@alicloud/log";
200
- async function query(session, options2) {
1084
+ async function query(session, options3) {
201
1085
  const temporary = await post(session, "/sls/session", {}, true);
202
- if (options2.from <= 0 || options2.to < options2.from || options2.to - options2.from > temporary.limits.maxTimeRangeSeconds) throw new Error("SLS time range exceeds the server limit");
1086
+ if (options3.from <= 0 || options3.to < options3.from || options3.to - options3.from > temporary.limits.maxTimeRangeSeconds) throw new Error("SLS time range exceeds the server limit");
203
1087
  const client = new LogClient({ endpoint: temporary.endpoint, use_https: true, accessKeyId: temporary.credentials.accessKeyId, accessKeySecret: temporary.credentials.accessKeySecret, securityToken: temporary.credentials.securityToken });
204
- const response = await client.getLogs(temporary.project, temporary.logstore, new Date(options2.from * 1e3), new Date(options2.to * 1e3), { query: options2.query, line: Math.min(options2.line || 50, temporary.limits.maxResults), offset: options2.offset || 0, reverse: options2.reverse });
1088
+ const response = await client.getLogs(temporary.project, temporary.logstore, new Date(options3.from * 1e3), new Date(options3.to * 1e3), { query: options3.query, line: Math.min(options3.line || 50, temporary.limits.maxResults), offset: options3.offset || 0, reverse: options3.reverse });
205
1089
  const logs = (response.body ?? response).map?.((row) => Object.fromEntries(Object.entries(row).map(([k, v]) => [k, String(v).slice(0, temporary.limits.maxMessageChars || void 0)]))) ?? response.body ?? response;
206
1090
  return { logs };
207
1091
  }
@@ -229,132 +1113,1323 @@ function publicTenant(t) {
229
1113
  }
230
1114
 
231
1115
  // src/update.ts
232
- import { spawn as spawn2 } from "child_process";
1116
+ import { spawn } from "child_process";
233
1117
  import { mkdir, writeFile } from "fs/promises";
234
1118
  import { homedir, platform } from "os";
235
- import { join as join2 } from "path";
236
- import { compareVersions } from "compare-versions";
237
- var exec = (command, args) => new Promise((done, reject) => {
238
- const p = spawn2(command, args, { stdio: "inherit" });
239
- p.on("error", reject);
240
- p.on("exit", (c) => c === 0 ? done() : reject(new Error(`${command} exited with ${c}`)));
1119
+ import { isAbsolute, join as join2 } from "path";
1120
+ var exec = (command, args, options3 = {}) => new Promise((resolve5, reject) => {
1121
+ const chunks = [];
1122
+ const child = spawn(command, args, {
1123
+ stdio: options3.capture ? ["ignore", "pipe", "inherit"] : "inherit"
1124
+ });
1125
+ if (options3.capture) child.stdout?.on("data", (chunk) => chunks.push(chunk));
1126
+ child.on("error", reject);
1127
+ child.on("exit", (code) => {
1128
+ if (code === 0 || options3.allowFailure) {
1129
+ resolve5(Buffer.concat(chunks).toString("utf8"));
1130
+ return;
1131
+ }
1132
+ reject(new Error(`${command} exited with ${code}`));
1133
+ });
241
1134
  });
1135
+ var xml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
1136
+ var systemdArg = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
1137
+ var windowsArg = (value) => /[\s"]/.test(value) ? `"${value.replaceAll('"', '\\"')}"` : value;
1138
+ function schedulerInvocation(environment2 = process.env, nodeExecutable = process.execPath) {
1139
+ const npmExecutable = environment2.npm_execpath;
1140
+ if (!npmExecutable || !isAbsolute(npmExecutable)) {
1141
+ throw new Error(
1142
+ "cannot register updater: run this command through npm or npx so npm_execpath is available"
1143
+ );
1144
+ }
1145
+ return {
1146
+ command: nodeExecutable,
1147
+ args: [
1148
+ npmExecutable,
1149
+ "exec",
1150
+ "--yes",
1151
+ "--package=@shulex/cxclawctl@latest",
1152
+ "--",
1153
+ "cxclawctl",
1154
+ "update",
1155
+ "--scheduled"
1156
+ ]
1157
+ };
1158
+ }
242
1159
  async function update() {
243
- const info = await fetch("https://registry.npmjs.org/@shulex%2Fcxclawctl/latest", { signal: AbortSignal.timeout(3e4) }).then((r) => {
244
- if (!r.ok) throw new Error(`npm registry returned ${r.status}`);
245
- return r.json();
246
- });
247
- if (compareVersions(info.version, VERSION) > 0) console.log(`\u53D1\u73B0\u65B0\u7248\u672C ${info.version}\uFF1Bnpx \u4E0B\u6B21\u8FD0\u884C\u4F1A\u81EA\u52A8\u4F7F\u7528\u6700\u65B0\u7248\u3002`);
248
1160
  await exec("codex", ["plugin", "marketplace", "upgrade", "cxclaw"]);
249
- return info.version;
1161
+ await exec("codex", ["plugin", "add", "cxclaw@cxclaw"]);
1162
+ const raw = await exec("codex", ["plugin", "list", "--json"], { capture: true });
1163
+ const list = JSON.parse(raw);
1164
+ const plugin = list.installed?.find((item) => item.pluginId === "cxclaw@cxclaw");
1165
+ if (!plugin?.version || plugin.enabled === false) {
1166
+ throw new Error("CXClaw plugin is not installed and enabled");
1167
+ }
1168
+ const response = await fetch(
1169
+ `https://registry.npmjs.org/@shulex%2Fcxclawctl/${encodeURIComponent(plugin.version)}`,
1170
+ { signal: AbortSignal.timeout(3e4) }
1171
+ );
1172
+ if (!response.ok) {
1173
+ throw new Error(
1174
+ `npm package @shulex/cxclawctl@${plugin.version} is unavailable (${response.status})`
1175
+ );
1176
+ }
1177
+ const metadata = await response.json();
1178
+ if (metadata.version !== plugin.version) {
1179
+ throw new Error(
1180
+ `npm returned ${metadata.version ?? "no version"}, expected ${plugin.version}`
1181
+ );
1182
+ }
1183
+ return {
1184
+ pluginVersion: plugin.version,
1185
+ cliPackageVersion: metadata.version,
1186
+ restartRequired: true
1187
+ };
250
1188
  }
251
1189
  async function installScheduler() {
252
- const command = process.platform === "win32" ? "npx.cmd" : "npx";
253
- const args = ["--yes", "@shulex/cxclawctl@latest", "update", "--scheduled"];
1190
+ const invocation = schedulerInvocation();
254
1191
  if (platform() === "darwin") {
255
1192
  const dir = join2(homedir(), "Library/LaunchAgents");
1193
+ const path = join2(dir, "com.solvea.cxclaw.update.plist");
1194
+ const programArguments = [invocation.command, ...invocation.args].map((value) => `<string>${xml(value)}</string>`).join("");
256
1195
  await mkdir(dir, { recursive: true });
257
- await writeFile(join2(dir, "com.solvea.cxclaw.update.plist"), `<?xml version="1.0"?><plist version="1.0"><dict><key>Label</key><string>com.solvea.cxclaw.update</string><key>ProgramArguments</key><array><string>${command}</string>${args.map((x) => `<string>${x}</string>`).join("")}</array><key>StartInterval</key><integer>21600</integer><key>RunAtLoad</key><true/></dict></plist>`);
258
- await exec("launchctl", ["load", join2(dir, "com.solvea.cxclaw.update.plist")]);
259
- } else if (platform() === "linux") {
1196
+ await writeFile(
1197
+ path,
1198
+ `<?xml version="1.0" encoding="UTF-8"?>
1199
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
1200
+ <plist version="1.0"><dict><key>Label</key><string>com.solvea.cxclaw.update</string><key>ProgramArguments</key><array>${programArguments}</array><key>StartInterval</key><integer>21600</integer><key>RunAtLoad</key><true/></dict></plist>
1201
+ `
1202
+ );
1203
+ await exec("launchctl", ["unload", path], { allowFailure: true });
1204
+ await exec("launchctl", ["load", path]);
1205
+ return;
1206
+ }
1207
+ if (platform() === "linux") {
260
1208
  const dir = join2(homedir(), ".config/systemd/user");
1209
+ const command = [invocation.command, ...invocation.args].map(systemdArg).join(" ");
261
1210
  await mkdir(dir, { recursive: true });
262
- await writeFile(join2(dir, "cxclaw-update.service"), `[Service]
1211
+ await writeFile(
1212
+ join2(dir, "cxclaw-update.service"),
1213
+ `[Service]
263
1214
  Type=oneshot
264
- ExecStart=${command} ${args.join(" ")}
265
- `);
266
- await writeFile(join2(dir, "cxclaw-update.timer"), "[Timer]\nOnBootSec=5m\nOnUnitActiveSec=6h\nRandomizedDelaySec=30m\nPersistent=true\n[Install]\nWantedBy=timers.target\n");
1215
+ ExecStart=${command}
1216
+ `
1217
+ );
1218
+ await writeFile(
1219
+ join2(dir, "cxclaw-update.timer"),
1220
+ "[Timer]\nOnBootSec=5m\nOnUnitActiveSec=6h\nPersistent=true\n[Install]\nWantedBy=timers.target\n"
1221
+ );
267
1222
  await exec("systemctl", ["--user", "daemon-reload"]);
268
1223
  await exec("systemctl", ["--user", "enable", "--now", "cxclaw-update.timer"]);
269
- } else await exec("schtasks", ["/Create", "/F", "/SC", "HOURLY", "/MO", "6", "/TN", "Solvea CXClaw Update", "/TR", `${command} ${args.join(" ")}`]);
1224
+ return;
1225
+ }
1226
+ const task = [invocation.command, ...invocation.args].map(windowsArg).join(" ");
1227
+ await exec("schtasks", [
1228
+ "/Create",
1229
+ "/F",
1230
+ "/SC",
1231
+ "HOURLY",
1232
+ "/MO",
1233
+ "6",
1234
+ "/TN",
1235
+ "Solvea CXClaw Update",
1236
+ "/TR",
1237
+ task
1238
+ ]);
270
1239
  }
271
1240
  async function installMarketplace(channel) {
272
- if (!["stable", "canary", "dev"].includes(channel)) throw new Error("invalid channel");
273
- await exec("codex", ["plugin", "marketplace", "add", "SolveaCX/cx_claw_codex", "--ref", `marketplace/${channel}`]).catch(() => exec("codex", ["plugin", "marketplace", "upgrade", "cxclaw"]));
274
- await exec("codex", ["plugin", "add", "cxclaw@cxclaw"]).catch(() => void 0);
1241
+ if (!["stable", "canary", "dev"].includes(channel)) {
1242
+ throw new Error("invalid channel");
1243
+ }
1244
+ await exec("codex", [
1245
+ "plugin",
1246
+ "marketplace",
1247
+ "add",
1248
+ "SolveaCX/cx_claw_codex",
1249
+ "--ref",
1250
+ `marketplace/${channel}`
1251
+ ]).catch(() => exec("codex", ["plugin", "marketplace", "upgrade", "cxclaw"]));
1252
+ await exec("codex", ["plugin", "add", "cxclaw@cxclaw"]);
275
1253
  }
276
1254
 
277
- // src/cli.ts
278
- var print = (value) => console.log(JSON.stringify(value, null, 2));
279
- async function main(args = process.argv.slice(2)) {
280
- const [command, sub, ...rest] = args;
281
- if (!command) {
282
- console.log("cxclawctl auth|tenant|api|sls|script|doctor|update|setup|version");
283
- return;
1255
+ // src/workflows/runtime.ts
1256
+ import { execFile } from "child_process";
1257
+ import { promises as fs } from "fs";
1258
+ import { join as join3, resolve as resolve2 } from "path";
1259
+ import { promisify } from "util";
1260
+ var exec2 = promisify(execFile);
1261
+ var workspace = () => resolve2(process.env.WORKSPACE_DIR ?? join3(process.cwd(), "workspace"));
1262
+ var root = () => join3(workspace(), "runtime-inspector");
1263
+ var dirs = () => ({ output: join3(root(), "outputs"), state: join3(root(), "state"), tmp: join3(root(), "tmp") });
1264
+ var timestamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1265
+ var readJson = async (path, fallback) => {
1266
+ try {
1267
+ return JSON.parse(await fs.readFile(path, "utf8"));
1268
+ } catch {
1269
+ return fallback;
284
1270
  }
285
- if (command === "version") return print({ pluginVersion: VERSION, cliVersion: VERSION, toolSchemaVersion: TOOL_SCHEMA_VERSION, serverApiVersion: SERVER_API_VERSION });
286
- if (command === "setup") {
287
- const server = option(args, "--server", true);
288
- const channel = option(args, "--channel") ?? "stable";
289
- await installMarketplace(channel);
290
- await login(server, channel);
291
- await installScheduler();
292
- return;
1271
+ };
1272
+ var writeJson = async (path, value) => {
1273
+ await fs.mkdir(resolve2(path, ".."), { recursive: true });
1274
+ await fs.writeFile(path, JSON.stringify(value, null, 2));
1275
+ };
1276
+ function check(label, ok, detail = "") {
1277
+ return { label, ok, ...detail ? { detail } : {} };
1278
+ }
1279
+ async function prepare(args) {
1280
+ const { tmp, state: state2 } = dirs();
1281
+ const source = option(args, "--source");
1282
+ const batchSize = Number(option(args, "--batch-size") ?? 10);
1283
+ if (!Number.isSafeInteger(batchSize) || batchSize <= 0) throw new Error("--batch-size must be a positive integer");
1284
+ let records;
1285
+ if (source) {
1286
+ const content = await fs.readFile(source, "utf8");
1287
+ if (source.toLowerCase().endsWith(".json")) {
1288
+ const parsed = JSON.parse(content);
1289
+ records = Array.isArray(parsed) ? parsed.map((item) => typeof item === "object" && item ? item : { text: String(item) }) : [parsed];
1290
+ } else if (source.toLowerCase().endsWith(".csv")) {
1291
+ const [header, ...lines] = content.split(/\r?\n/).filter(Boolean).map((line) => line.split(","));
1292
+ records = lines.map((values) => Object.fromEntries((header ?? []).map((key, i) => [key, values[i] ?? ""])));
1293
+ } else records = content.split(/\r?\n/).filter(Boolean).map((text) => ({ text }));
1294
+ } else records = Array.from({ length: 30 }, (_, i) => ({ id: i + 1, text: `\u6D4B\u8BD5\u8BB0\u5F55 #${i + 1}`, value: (i + 1) * 10 }));
1295
+ await fs.rm(tmp, { recursive: true, force: true });
1296
+ await fs.mkdir(tmp, { recursive: true });
1297
+ const batches = [];
1298
+ for (let i = 0; i < records.length; i += batchSize) batches.push(records.slice(i, i + batchSize));
1299
+ await Promise.all(batches.map((batch, i) => writeJson(join3(tmp, `batch_${String(i).padStart(3, "0")}.json`), batch)));
1300
+ await writeJson(join3(state2, "inspect.json"), { status: "batched", total_records: records.length, total_batches: batches.length, batch_size: batchSize, source: source ?? "auto-generated", written_at: (/* @__PURE__ */ new Date()).toISOString() });
1301
+ return { status: "batched", totalRecords: records.length, totalBatches: batches.length, tmp };
1302
+ }
1303
+ async function processBatches() {
1304
+ const { tmp, output, state: state2 } = dirs();
1305
+ const current = await readJson(join3(state2, "inspect.json"), {});
1306
+ if (current.status !== "batched") throw new Error(`runtime state must be batched, got ${String(current.status ?? "missing")}`);
1307
+ const names = (await fs.readdir(tmp)).filter((name) => /^batch_\d+\.json$/.test(name)).sort();
1308
+ if (!names.length) throw new Error(`no batch files found in ${tmp}`);
1309
+ const records = [];
1310
+ for (const name of names) for (const row of await readJson(join3(tmp, name), [])) records.push({ ...row, _processed: true, _summary: `processed: ${JSON.stringify(row).slice(0, 60)}`, _at: (/* @__PURE__ */ new Date()).toISOString() });
1311
+ const path = join3(output, `results_${timestamp()}.json`);
1312
+ await writeJson(path, { total: records.length, processed_at: (/* @__PURE__ */ new Date()).toISOString(), source: current.source, records });
1313
+ await writeJson(join3(state2, "inspect.json"), { status: "done", total_processed: records.length, results_path: path, done_at: (/* @__PURE__ */ new Date()).toISOString() });
1314
+ return { status: "done", total: records.length, resultsPath: path };
1315
+ }
1316
+ async function state() {
1317
+ const { state: stateDir2, output, tmp } = dirs();
1318
+ return { state: await readJson(join3(stateDir2, "inspect.json"), null), outputFiles: await fs.readdir(output).catch(() => []), tmpFiles: await fs.readdir(tmp).catch(() => []) };
1319
+ }
1320
+ async function verify() {
1321
+ const snapshot = await state();
1322
+ const checks = [check("state \u6587\u4EF6\u5DF2\u8FD8\u539F", Boolean(snapshot.state)), check("status == done", snapshot.state?.status === "done", `actual=${String(snapshot.state?.status)}`), check("outputs \u76EE\u5F55\u53EF\u8BFB", Array.isArray(snapshot.outputFiles)), check("\u81F3\u5C11\u4E00\u4E2A results \u6587\u4EF6", snapshot.outputFiles.some((name) => name.startsWith("results_")))];
1323
+ return { ok: checks.every((item) => item.ok), checks };
1324
+ }
1325
+ async function sandbox(args) {
1326
+ const scenario = option(args, "--scenario") ?? "all";
1327
+ const d = dirs();
1328
+ const scenarios = scenario === "all" ? ["env", "fs", "execute", "paths", "deps"] : [scenario];
1329
+ const checks = [];
1330
+ for (const item of scenarios) {
1331
+ if (item === "env") checks.push(check("WORKSPACE_DIR", Boolean(process.env.WORKSPACE_DIR ?? workspace())), check("\u654F\u611F\u53D8\u91CF\u672A\u76F4\u63A5\u8F93\u51FA", true));
1332
+ else if (["fs", "paths"].includes(item)) {
1333
+ await Promise.all(Object.values(d).map((path) => fs.mkdir(path, { recursive: true })));
1334
+ checks.push(...Object.entries(d).map(([name, path]) => check(`${name} \u76EE\u5F55\u53EF\u5199`, true, path)));
1335
+ } else if (item === "execute") {
1336
+ const result = await exec2("sh", ["-c", "printf runtime-ok"]);
1337
+ checks.push(check("shell \u6267\u884C\u94FE\u8DEF", result.stdout === "runtime-ok"));
1338
+ } else if (item === "deps") checks.push(check("Node runtime", Number(process.versions.node.split(".")[0]) >= 22, process.versions.node));
1339
+ else throw new Error(`unknown runtime sandbox scenario: ${item}`);
1340
+ }
1341
+ return { ok: checks.every((item) => item.ok), scenario, checks };
1342
+ }
1343
+ async function model(args) {
1344
+ if (option(args, "--scenario", true) !== "truncation") throw new Error("only --scenario truncation is supported");
1345
+ const target = join3(dirs().tmp, "truncation_test.md");
1346
+ return { scenario: "truncation", target, instruction: "Use the Codex write_file tool to write 60+ long technical paragraphs, then inspect SLG model_response stop_reason and output_tokens." };
1347
+ }
1348
+ async function runRuntime(action2, args) {
1349
+ if (action2 === "prepare") return prepare(args);
1350
+ if (action2 === "process") return processBatches();
1351
+ if (action2 === "state") return state();
1352
+ if (action2 === "verify") return verify();
1353
+ if (action2 === "sandbox") return sandbox(args);
1354
+ if (action2 === "model") return model(args);
1355
+ if (action2 === "write-test") {
1356
+ const { output, state: stateDir2 } = dirs();
1357
+ const runId = timestamp();
1358
+ await writeJson(join3(output, `${runId}_test.json`), { run_id: runId, written_at: (/* @__PURE__ */ new Date()).toISOString() });
1359
+ const current = await readJson(join3(stateDir2, "inspect.json"), {});
1360
+ await writeJson(join3(stateDir2, "inspect.json"), { ...current, last_run_id: runId, write_count: Number(current.write_count ?? 0) + 1 });
1361
+ return { ok: true, runId };
1362
+ }
1363
+ throw new Error("runtime action must be prepare, process, state, verify, sandbox, model, or write-test");
1364
+ }
1365
+
1366
+ // src/workflows/solvea-kit.ts
1367
+ import ExcelJS from "exceljs";
1368
+ import { promises as fs2 } from "fs";
1369
+ import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
1370
+ var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ?? join4(process.cwd(), "workspace"));
1371
+ var outputDir = (owner) => join4(workspace2(), "outputs", owner);
1372
+ var stateDir = (owner) => join4(workspace2(), "state", owner);
1373
+ var now = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1374
+ var readJson2 = async (path) => JSON.parse(await fs2.readFile(path, "utf8"));
1375
+ var writeJson2 = async (path, value) => {
1376
+ await fs2.mkdir(dirname2(path), { recursive: true });
1377
+ await fs2.writeFile(path, JSON.stringify(value, null, 2));
1378
+ };
1379
+ var INIT_NOTICE = `The information of this row cannot be deleted! Tips:
1380
+ 1. first_level is the first level that is not empty.
1381
+ 2. second_level is the second level.
1382
+ 3. third_level is the third level.
1383
+ 4. fourth_level is the fourth level.
1384
+ 5. "Name", "describe" and "example" are for the use of the large model. Do not repeat them.`;
1385
+ var UPDATE_NOTICE = `The information of this row cannot be deleted! Tips:
1386
+ 1. The "id" is automatically generated by the program. When it is empty, it indicates adding a new tag.
1387
+ 2. "Name", "describe" and "example" are for the use of the large model. Do not repeat them.
1388
+ 3. Fill in the "parent_ID" with the ID of the parent node tag.`;
1389
+ function examples(label) {
1390
+ const values = label.examples ?? label.exampleList ?? [];
1391
+ if (!Array.isArray(values)) throw new Error("examples must be an array");
1392
+ return [...values.slice(0, 5).map(String), ...Array(Math.max(0, 5 - values.length)).fill("")];
1393
+ }
1394
+ function labelsFrom(value) {
1395
+ const labels = value && typeof value === "object" && !Array.isArray(value) ? value.labels : value;
1396
+ if (!Array.isArray(labels) || !labels.length || labels.some((item) => !item || typeof item !== "object")) throw new Error("input requires a non-empty labels array");
1397
+ return labels;
1398
+ }
1399
+ async function generateLabelImport(args) {
1400
+ const input = option(args, "--input") ?? option(args, "--data-file", true);
1401
+ const init = args.includes("--init");
1402
+ const output = option(args, "--output") ?? join4(stateDir("solvea-kit"), init ? "labels_init.xlsx" : "labels_update.xlsx");
1403
+ const labels = labelsFrom(await readJson2(input));
1404
+ const workbook = new ExcelJS.Workbook();
1405
+ const sheet = workbook.addWorksheet("labels");
1406
+ if (init) {
1407
+ sheet.addRow([INIT_NOTICE]);
1408
+ sheet.addRow(["first_level", "second_level", "third_level", "fourth_level", "describe", "example1", "example2", "example3", "example4", "example5"]);
1409
+ for (const label of labels) {
1410
+ const path = label.path ?? [label.firstLevel ?? label.first_level ?? "", label.secondLevel ?? label.second_level ?? "", label.thirdLevel ?? label.third_level ?? "", label.fourthLevel ?? label.fourth_level ?? ""];
1411
+ if (!String(path[0] ?? "").trim()) throw new Error("init labels require path or first_level/firstLevel");
1412
+ sheet.addRow([...path.slice(0, 4).map((value) => String(value ?? "").trim()), label.describe ?? "", ...examples(label)]);
1413
+ }
1414
+ } else {
1415
+ sheet.addRow([UPDATE_NOTICE]);
1416
+ sheet.addRow(["id", "name", "describe", "example1", "example2", "example3", "example4", "example5", "is_tag", "level", "parent_id", "path"]);
1417
+ for (const label of labels) {
1418
+ const name = label.name ?? label.nodeName;
1419
+ if (!name) throw new Error("update labels require name or nodeName");
1420
+ const isTag = typeof (label.isTag ?? label.is_tag ?? 1) === "boolean" ? label.isTag ?? label.is_tag ? 1 : 0 : label.isTag ?? label.is_tag ?? 1;
1421
+ sheet.addRow([label.id ?? "", name, label.describe ?? label.nodeDescribe ?? "", ...examples(label), isTag, label.level ?? "", label.parentId ?? label.parent_id ?? 0, label.path ?? ""]);
1422
+ }
1423
+ }
1424
+ sheet.getRow(1).font = { bold: true, color: { argb: "FF9C6500" } };
1425
+ sheet.getRow(1).height = 78;
1426
+ sheet.getRow(2).font = { bold: true };
1427
+ sheet.columns.forEach((column) => {
1428
+ column.width = 18;
1429
+ });
1430
+ await fs2.mkdir(dirname2(output), { recursive: true });
1431
+ await workbook.xlsx.writeFile(output);
1432
+ return { file: output, format: init ? "init" : "update", rows: labels.length };
1433
+ }
1434
+ var TAXONOMY = { "Pre-Sales Inquiry": ["Product Recommendation", "Discount Inquiry", "Price Inquiry", "Stock Availability", "Payment Issues"], Invoices: ["Request Invoice", "Modify Invoice Information"], "Order Issues": ["Modify Order", "Check Order Status", "Cancel Order"], "Logistics Issues": ["Track Shipment", "Shipping Exception"], "Package issues": ["Missing Items", "Wrong Items Received", "Damaged Package"], "Product issues": ["Product Usage", "Physical Damage", "Non-Physical Issues"], "Return and exchange": [] };
1435
+ async function classifyIntents(args) {
1436
+ const owner = option(args, "--owner") ?? "solvea-kit";
1437
+ const runId = option(args, "--run-id") ?? now();
1438
+ const noExcel = args.includes("--no-excel");
1439
+ if (!noExcel && !option(args, "--xlsx")) throw new Error("provide --xlsx or --no-excel");
1440
+ const intents = Object.entries(TAXONOMY).map(([name, l2s]) => ({ name, definition: `Customer requests and issues related to ${name}.`, count: 0, pct: 0, sub_intents: l2s.map((l2) => ({ name: l2, definition: "", count: 0, pct: 0, samples: [], is_new: false })), samples: [], is_new: false }));
1441
+ const result = { meta: { run_id: runId, total: 0, classified: 0, n_known: intents.length, n_new: 0, mode: noExcel ? "no-excel" : "structured" }, intents, new_intents: [] };
1442
+ const resultPath = join4(outputDir(owner), `results_${runId}.json`);
1443
+ await writeJson2(resultPath, result);
1444
+ await writeJson2(join4(stateDir(owner), "progress.json"), { status: "ready", run_id: runId, results_path: resultPath, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1445
+ return { ...result.meta, resultsPath: resultPath };
1446
+ }
1447
+ async function runSolveaKitWorkflow(action2, args) {
1448
+ if (action2 === "label-import") return generateLabelImport(args);
1449
+ if (action2 === "intent-classify") return classifyIntents(args);
1450
+ throw new Error("workflow action must be label-import or intent-classify");
1451
+ }
1452
+
1453
+ // src/workflows/support.ts
1454
+ import { readFile as readFile3 } from "fs/promises";
1455
+ import { basename as basename2 } from "path";
1456
+ var safe = (value) => encodeURIComponent(value);
1457
+ var docsMcpUrl = process.env.CXCLAW_DOCS_MCP_URL ?? "https://solvea-39f11a36.mintlify.app/mcp";
1458
+ var publicDocsPrefix = "https://www.voc.ai/cn/docs/";
1459
+ var previewDocsPrefix = "https://solvea-39f11a36.mintlify.app/";
1460
+ async function docsTool(tool, arguments_) {
1461
+ const requestId = Date.now();
1462
+ const initialize = await fetch(docsMcpUrl, { method: "POST", headers: { accept: "application/json, text/event-stream", "content-type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", id: requestId, method: "initialize", params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "cxclawctl", version: "1" } } }), signal: AbortSignal.timeout(3e4) });
1463
+ const sessionId = initialize.headers.get("mcp-session-id");
1464
+ const headers = { accept: "application/json, text/event-stream", "content-type": "application/json", ...sessionId ? { "mcp-session-id": sessionId } : {} };
1465
+ await fetch(docsMcpUrl, { method: "POST", headers, body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized", params: {} }), signal: AbortSignal.timeout(3e4) });
1466
+ const response = await fetch(docsMcpUrl, { method: "POST", headers, body: JSON.stringify({ jsonrpc: "2.0", id: requestId + 1, method: "tools/call", params: { name: tool, arguments: arguments_ } }), signal: AbortSignal.timeout(3e4) });
1467
+ const text = await response.text();
1468
+ if (!response.ok) throw new Error(`product docs request failed: HTTP ${response.status}`);
1469
+ const dataLine = text.split(/\r?\n/).find((line) => line.startsWith("data:"));
1470
+ try {
1471
+ const payload = JSON.parse(dataLine ? dataLine.slice(5).trim() : text);
1472
+ if (payload.error) throw new Error(String(payload.error.message ?? "product docs request failed"));
1473
+ return payload.result ?? payload;
1474
+ } catch {
1475
+ return { content: [{ type: "text", text }] };
1476
+ }
1477
+ }
1478
+ function normalizeDocUrl(value) {
1479
+ if (!value.startsWith(previewDocsPrefix)) return value;
1480
+ let path = value.slice(previewDocsPrefix.length);
1481
+ const hash = path.indexOf("#");
1482
+ const fragment = hash >= 0 ? path.slice(hash) : "";
1483
+ if (hash >= 0) path = path.slice(0, hash);
1484
+ if (path.startsWith("solvea/bot_cn/")) return `${publicDocsPrefix}bot/${path.split("/").pop()}${fragment}`;
1485
+ return `${publicDocsPrefix}${path}${fragment}`;
1486
+ }
1487
+ function textBlocks(value) {
1488
+ const content = value && typeof value === "object" ? value.content : void 0;
1489
+ return Array.isArray(content) ? content.flatMap((item) => item && typeof item === "object" && typeof item.text === "string" ? [String(item.text)] : []) : [];
1490
+ }
1491
+ function parseDocBlock(text) {
1492
+ const result = {};
1493
+ const content = [];
1494
+ let inContent = false;
1495
+ for (const line of text.split(/\r?\n/)) {
1496
+ if (inContent) content.push(line);
1497
+ else if (line.startsWith("Title: ")) result.title = line.slice(7).trim();
1498
+ else if (line.startsWith("Link: ")) result.url = normalizeDocUrl(line.slice(6).trim());
1499
+ else if (line.startsWith("Page: ")) result.page = line.slice(6).trim();
1500
+ else if (line.startsWith("Content:")) {
1501
+ inContent = true;
1502
+ if (line.slice(8).trim()) content.push(line.slice(8).trim());
1503
+ }
1504
+ }
1505
+ if (content.length) result.content = content.join("\n").trim();
1506
+ return Object.keys(result).length ? result : { content: text };
1507
+ }
1508
+ async function request2(session, method, path, body) {
1509
+ const tenant = session.tenant;
1510
+ const base = tenant?.businessUrl?.replace(/\/$/, "");
1511
+ if (!tenant || !base || !tenant.businessToken) throw new Error("no tenant selected");
1512
+ const cookie = tenant.environment === "prod" ? "_token" : "_token_staging";
1513
+ const response = await fetch(`${base}/api_v2/gpt${path}`, { method, headers: { accept: "application/json", ...body === void 0 ? {} : { "content-type": "application/json" }, cookie: `${cookie}=${tenant.businessToken}` }, body: body === void 0 ? void 0 : JSON.stringify(body), signal: AbortSignal.timeout(3e4) });
1514
+ const value = await response.json().catch(() => ({}));
1515
+ if (!response.ok || value.code !== void 0 && ![0, 200, "0", "200", "OK", "SUCCESS"].includes(value.code)) throw new Error(`support API failed: HTTP ${response.status}`);
1516
+ return value.data ?? value;
1517
+ }
1518
+ function portal(session) {
1519
+ return session.tenant?.environment === "prod" ? "https://ai.solvea.cx" : "https://ai-staging.solvea.cx";
1520
+ }
1521
+ async function runSupport(session, action2, args) {
1522
+ if (action2 === "list-tickets") return request2(session, "POST", "/support/tickets", { page: Number(option(args, "--page") ?? 1), pageSize: Number(option(args, "--page-size") ?? 20) });
1523
+ if (action2 === "get-ticket") return request2(session, "GET", `/support/tickets/${safe(option(args, "--ticket-number", true))}`);
1524
+ if (action2 === "append-message") return request2(session, "POST", `/support/tickets/${safe(option(args, "--ticket-number", true))}/messages`, { content: option(args, "--content", true) });
1525
+ if (action2 === "create-ticket") {
1526
+ const attachments = [];
1527
+ for (const file of options2(args, "--attachment")) {
1528
+ const form = new FormData();
1529
+ form.append("file", new Blob([await readFile3(file)]), basename2(file));
1530
+ const tenant = session.tenant;
1531
+ const base = tenant?.businessUrl?.replace(/\/$/, "");
1532
+ if (!tenant || !base || !tenant.businessToken) throw new Error("no tenant selected");
1533
+ const cookie = tenant.environment === "prod" ? "_token" : "_token_staging";
1534
+ const uploaded = await fetch(`${base}/api_v2/gpt/support/tickets/attachments/upload`, { method: "POST", headers: { cookie: `${cookie}=${tenant.businessToken}` }, body: form, signal: AbortSignal.timeout(3e4) });
1535
+ const payload = await uploaded.json();
1536
+ if (!uploaded.ok) throw new Error(`attachment upload failed: HTTP ${uploaded.status}`);
1537
+ attachments.push(payload.data ?? payload);
1538
+ }
1539
+ const sourceId = process.env.CHAT_ID ?? "";
1540
+ if (!sourceId) throw new Error("CHAT_ID is not configured");
1541
+ const ticket = await request2(session, "POST", "/support/tickets/create", { content: option(args, "--content", true), sourceType: "cxclaw", sourceId, brand: option(args, "--brand"), issueType: option(args, "--issue-type") ?? option(args, "--category"), subject: option(args, "--subject"), contactEmail: option(args, "--contact-email"), ...option(args, "--ext") ? { extFields: JSON.parse(option(args, "--ext")) } : {}, ...attachments.length ? { attachments } : {} });
1542
+ const number = ticket.ticketNumber;
1543
+ await request2(session, "POST", "/support/skill-metrics", { chatId: sourceId, ticketNumber: number }).catch(() => void 0);
1544
+ return { ticketNumber: number, ticketDetailUrl: number ? `${portal(session)}/chatbot#/support/tickets/${number}` : void 0, status: ticket.status, subject: ticket.subject, issueType: ticket.issueType, createdAt: ticket.createdAt };
1545
+ }
1546
+ if (action2 === "search-docs") {
1547
+ const query2 = option(args, "--query", true);
1548
+ const result = await docsTool("search_solvea", { query: query2 });
1549
+ return { query: query2, results: textBlocks(result).map(parseDocBlock) };
1550
+ }
1551
+ if (action2 === "query-docs-filesystem") {
1552
+ const command = option(args, "--command", true);
1553
+ const result = await docsTool("query_docs_filesystem_solvea", { command });
1554
+ return { command, output: textBlocks(result) };
1555
+ }
1556
+ throw new Error("support action must be search-docs, list-tickets, get-ticket, create-ticket, or append-message");
1557
+ }
1558
+
1559
+ // src/workflows/common.ts
1560
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
1561
+ import { dirname as dirname3, join as join5, resolve as resolve4 } from "path";
1562
+ import { homedir as homedir2 } from "os";
1563
+ var workspaceRoot = () => resolve4(process.env.CXCLAW_WORKSPACE ?? join5(homedir2(), ".cxclaw", "workspace"));
1564
+ var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ?? join5(workspaceRoot(), "state"), domain);
1565
+ var outputRoot = (domain) => resolve4(process.env.CXCLAW_OUTPUT_DIR ?? join5(workspaceRoot(), "outputs"), domain);
1566
+ async function ensureParent(file) {
1567
+ await mkdir2(dirname3(file), { recursive: true });
1568
+ }
1569
+ async function ensureDir(directory) {
1570
+ await mkdir2(directory, { recursive: true });
1571
+ }
1572
+ async function readJson3(file) {
1573
+ return JSON.parse(await readFile4(file, "utf8"));
1574
+ }
1575
+ async function writeJson3(file, value) {
1576
+ await ensureParent(file);
1577
+ await writeFile2(file, `${JSON.stringify(value, null, 2)}
1578
+ `, "utf8");
1579
+ }
1580
+ function intOption(args, name, fallback) {
1581
+ const raw = option(args, name);
1582
+ if (raw === void 0) return fallback;
1583
+ const value = Number(raw);
1584
+ if (!Number.isFinite(value)) throw new Error(`${name} must be a number`);
1585
+ return value;
1586
+ }
1587
+ function safeJson(value) {
1588
+ return JSON.stringify(value, null, 2);
1589
+ }
1590
+ function htmlEscape(value) {
1591
+ return String(value ?? "").replace(/[&<>\"']/g, (char) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[char]);
1592
+ }
1593
+ async function writeHtml(file, title, body) {
1594
+ await ensureParent(file);
1595
+ await writeFile2(file, `<!doctype html><html><head><meta charset="utf-8"><title>${htmlEscape(title)}</title><style>body{font-family:system-ui,sans-serif;margin:2rem;line-height:1.5}pre{white-space:pre-wrap;background:#f6f8fa;padding:1rem;border-radius:8px}.card{border:1px solid #ddd;border-radius:8px;padding:1rem;margin:1rem 0}</style></head><body><h1>${htmlEscape(title)}</h1>${body}</body></html>`, "utf8");
1596
+ }
1597
+ function asRows(value) {
1598
+ if (Array.isArray(value)) return value.filter((item) => item && typeof item === "object");
1599
+ if (value && typeof value === "object") {
1600
+ const object = value;
1601
+ for (const key of ["list", "rows", "items", "data", "records", "result"]) {
1602
+ if (Array.isArray(object[key])) return object[key].filter((item) => item && typeof item === "object");
1603
+ }
293
1604
  }
294
- if (command === "auth" || command === "login" || command === "logout") {
295
- const action = command === "auth" ? sub : command;
296
- if (action === "login") {
297
- const channel = option(rest, "--channel") ?? "stable";
298
- return print(await login(option(rest, "--server", true), channel));
1605
+ return [];
1606
+ }
1607
+
1608
+ // src/workflows/agent-builder.ts
1609
+ function graphNodes(graph) {
1610
+ if (!graph || typeof graph !== "object") return [];
1611
+ const root2 = graph;
1612
+ for (const key of ["nodes", "nodeList", "blocks"]) if (Array.isArray(root2[key])) return root2[key].filter((x) => x && typeof x === "object");
1613
+ return [];
1614
+ }
1615
+ function graphEdges(graph) {
1616
+ if (!graph || typeof graph !== "object") return [];
1617
+ const root2 = graph;
1618
+ for (const key of ["edges", "connections", "lines"]) if (Array.isArray(root2[key])) return root2[key].filter((x) => x && typeof x === "object");
1619
+ return [];
1620
+ }
1621
+ function validateGraph(graph) {
1622
+ const errors = [], warnings = [];
1623
+ if (!graph || typeof graph !== "object" || Array.isArray(graph)) errors.push("graph must be a JSON object");
1624
+ const nodes = graphNodes(graph), edges = graphEdges(graph);
1625
+ if (!nodes.length) warnings.push("graph contains no nodes");
1626
+ const ids = /* @__PURE__ */ new Set();
1627
+ for (const [index, node] of nodes.entries()) {
1628
+ const id = String(node.id ?? node.nodeId ?? node.key ?? "");
1629
+ if (!id) errors.push(`nodes[${index}] is missing id`);
1630
+ else if (ids.has(id)) errors.push(`duplicate node id: ${id}`);
1631
+ else ids.add(id);
1632
+ if (!node.type && !node.nodeType && !node.kind) warnings.push(`nodes[${index}] is missing type`);
1633
+ }
1634
+ for (const [index, edge] of edges.entries()) {
1635
+ const from = String(edge.source ?? edge.sourceId ?? edge.from ?? edge.start ?? "");
1636
+ const to = String(edge.target ?? edge.targetId ?? edge.to ?? edge.end ?? "");
1637
+ if (!from || !to) errors.push(`edges[${index}] must contain source and target`);
1638
+ else {
1639
+ if (!ids.has(from)) errors.push(`edge ${index} references unknown source ${from}`);
1640
+ if (!ids.has(to)) errors.push(`edge ${index} references unknown target ${to}`);
299
1641
  }
300
- if (action === "logout") {
301
- await logout();
302
- return print({ ok: true, loggedOut: true });
1642
+ }
1643
+ return { valid: errors.length === 0, errors, warnings, nodeCount: nodes.length, edgeCount: edges.length };
1644
+ }
1645
+ function mergeDeep(base, patch) {
1646
+ if (Array.isArray(base) && Array.isArray(patch)) return [...base, ...patch];
1647
+ if (base && patch && typeof base === "object" && typeof patch === "object" && !Array.isArray(base) && !Array.isArray(patch)) {
1648
+ const out = { ...base };
1649
+ for (const [key, value] of Object.entries(patch)) out[key] = key in out ? mergeDeep(out[key], value) : value;
1650
+ return out;
1651
+ }
1652
+ return patch;
1653
+ }
1654
+ async function inspect(client, args) {
1655
+ if (!client) throw new Error("inspect requires an authenticated tenant");
1656
+ const agentId = option(args, "--agent-id");
1657
+ const agentName = option(args, "--agent-name");
1658
+ if (!agentId && !agentName) throw new Error("inspect requires --agent-id or --agent-name");
1659
+ let agent;
1660
+ if (agentId) agent = await client.getAgent(agentId);
1661
+ else {
1662
+ const result2 = await client.listAgents("text");
1663
+ const rows = Array.isArray(result2) ? result2 : result2?.list;
1664
+ agent = Array.isArray(rows) ? rows.find((row) => String(row.name ?? row.agentName) === agentName) : void 0;
1665
+ if (!agent) throw new Error(`agent not found: ${agentName}`);
1666
+ }
1667
+ const item = Array.isArray(agent) ? agent[0] : agent;
1668
+ const id = String(item?.id ?? item?.agentId ?? agentId ?? "");
1669
+ const graph = id ? await client.getChatflowGraph(id) : void 0;
1670
+ const result = { agent: item, graph };
1671
+ const out = option(args, "--out");
1672
+ if (out) await writeJson3(out, graph);
1673
+ return result;
1674
+ }
1675
+ async function chatflow(client, action2, args) {
1676
+ if (action2 === "inspect") return inspect(client, args);
1677
+ if (action2 === "validate") {
1678
+ const file = option(args, "--graph-file") ?? option(args, "--data-file", true);
1679
+ const graph = await readJson3(file);
1680
+ return { ...validateGraph(graph), file };
1681
+ }
1682
+ if (action2 === "compile") {
1683
+ const source = await readJson3(option(args, "--source-file", true));
1684
+ const graph = await readJson3(option(args, "--graph-file", true));
1685
+ const result = mergeDeep(graph, source);
1686
+ const validation = validateGraph(result);
1687
+ if (!validation.valid) throw new Error(`compiled graph is invalid: ${validation.errors.join("; ")}`);
1688
+ await writeJson3(option(args, "--graph-file", true), result);
1689
+ return { ...validation, graph: result };
1690
+ }
1691
+ if (action2 === "merge-source") {
1692
+ const integration = await readJson3(option(args, "--integration-file", true));
1693
+ let result = integration;
1694
+ for (const fragment of options2(args, "--fragment-file")) result = mergeDeep(result, await readJson3(fragment));
1695
+ await writeJson3(option(args, "--out-file", true), result);
1696
+ return { output: option(args, "--out-file"), ...validateGraph(result) };
1697
+ }
1698
+ if (["deploy", "update", "publish"].includes(action2)) {
1699
+ const graph = await readJson3(option(args, "--graph-file", true));
1700
+ const validation = validateGraph(graph);
1701
+ if (!validation.valid) throw new Error(`graph validation failed: ${validation.errors.join("; ")}`);
1702
+ if (!client) throw new Error("this chatflow action requires an authenticated tenant");
1703
+ if (action2 === "deploy") return client.createAgent({ name: option(args, "--agent-name", true), type: "CHAT_FLOW", meta: { chatFlowGraph: graph } });
1704
+ const id = option(args, "--agent-id", true);
1705
+ return client.updateChatflow(id, graph, action2 === "publish");
1706
+ }
1707
+ throw new Error(`unknown chatflow action: ${action2}`);
1708
+ }
1709
+ async function validateTool(args) {
1710
+ const value = await readJson3(option(args, "--data-file", true));
1711
+ const errors = [], warnings = [];
1712
+ if (!value || typeof value !== "object" || Array.isArray(value)) errors.push("tool payload must be an object");
1713
+ else {
1714
+ const object = value;
1715
+ if (!object.name && !object.pluginName) errors.push("tool name is required");
1716
+ if (!object.config && !object.externalHttpCallConfig && !object.url) warnings.push("tool has no HTTP configuration");
1717
+ }
1718
+ return { valid: errors.length === 0, errors, warnings };
1719
+ }
1720
+ async function runAgentBuilder(session, action2, args) {
1721
+ if (!action2) throw new Error("agent-builder action is required");
1722
+ if (action2 === "chatflow") {
1723
+ const operation = options2(args, "--operation")[0] ?? args.find((value) => ["inspect", "validate", "compile", "merge-source", "deploy", "update", "publish"].includes(value)) ?? "inspect";
1724
+ return chatflow(["validate", "compile", "merge-source"].includes(operation) ? void 0 : session ? new SolveaClient(session) : void 0, operation, args);
1725
+ }
1726
+ if (["validate", "compile", "merge-source"].includes(action2)) return chatflow(void 0, action2, args);
1727
+ if (["inspect", "deploy", "update", "publish"].includes(action2)) return chatflow(session ? new SolveaClient(session) : void 0, action2, args);
1728
+ if (action2 === "validate-tool") return validateTool(args);
1729
+ if (action2 === "migration" || action2 === "replay") return runLocalAgentWorkflow(action2, args);
1730
+ if (!session) throw new Error(`${action2} requires an authenticated tenant`);
1731
+ const client = new SolveaClient(session);
1732
+ if (action2 === "copy-marketplace") {
1733
+ const ids = options2(args, "--square-id");
1734
+ if (!ids.length) throw new Error("--square-id is required");
1735
+ if (flag(args, "--dry-run")) return { dryRun: true, squareIds: ids };
1736
+ const results = [];
1737
+ for (const id of ids) results.push(await client.rawCall("POST", "/api_v2/gpt/ap/copySquareAgent", { squareAgentId: Number(id), projectId: Number(await client.projectId()) }));
1738
+ return { squareIds: ids, results };
1739
+ }
1740
+ if (action2 === "patch-tools") {
1741
+ const ids = options2(args, "--agent-id");
1742
+ if (!ids.length) throw new Error("--agent-id is required");
1743
+ const headers = options2(args, "--header").map((value) => {
1744
+ const index = value.indexOf("=");
1745
+ return index < 1 ? { name: value, value: "" } : { name: value.slice(0, index), value: value.slice(index + 1) };
1746
+ });
1747
+ if (flag(args, "--dry-run")) return { dryRun: true, agentIds: ids, headers };
1748
+ const results = [];
1749
+ for (const id of ids) {
1750
+ const agent = await client.getAgent(id);
1751
+ const item = Array.isArray(agent) ? agent[0] : agent;
1752
+ const tools = Array.isArray(item?.tools) ? item.tools : [];
1753
+ const changed = tools.map((tool) => ({ ...tool, headers: [...Array.isArray(tool.headers) ? tool.headers : [], ...headers] }));
1754
+ results.push(await client.updateAgent({ ...item, agentId: Number(id), tools: changed }));
1755
+ }
1756
+ return { agentIds: ids, results };
1757
+ }
1758
+ throw new Error(`unknown agent-builder action: ${action2}`);
1759
+ }
1760
+ async function runLocalAgentWorkflow(action2, args) {
1761
+ if (action2 === "migration") {
1762
+ const operation = option(args, "--operation") ?? args.find((value2) => ["inspect", "emit-chunk-context", "prepare-batch", "prepare-batches", "merge-batch-plans", "emit-batch-context", "emit-mapping-mermaid", "validate-migration-plan", "validate-prompt-block-rendering", "audit-migration-source", "emit-handoff", "verify-handoff", "coverage-report", "update-progress", "update-batch-progress"].includes(value2)) ?? "inspect";
1763
+ if (operation === "update-progress" || operation === "update-batch-progress") {
1764
+ const file = option(args, "--progress-file", true);
1765
+ const progress = await readJson3(file).catch(() => ({}));
1766
+ const id = option(args, operation === "update-progress" ? "--chunk-id" : "--batch-id", true);
1767
+ const status = option(args, "--status", true);
1768
+ const key = operation === "update-progress" ? "chunks" : "batches";
1769
+ const entries = Array.isArray(progress[key]) ? progress[key] : [];
1770
+ const existing = entries.find((entry2) => String(entry2.id ?? entry2.chunkId ?? entry2.batchId) === id);
1771
+ if (existing) existing.status = status;
1772
+ else entries.push({ id, status, note: option(args, "--note"), artifacts: options2(args, "--artifact") });
1773
+ progress[key] = entries;
1774
+ await writeJson3(file, progress);
1775
+ return { operation, id, status, file };
303
1776
  }
304
- if (action === "status") {
1777
+ const input2 = option(args, "--input") ?? option(args, "--plan-file") ?? option(args, "--source-file") ?? option(args, "--index-file");
1778
+ if (!input2) throw new Error("migration requires --input or a plan/source file");
1779
+ const value = await readJson3(input2);
1780
+ if (["validate", "validate-plan", "validate-migration-plan", "audit", "audit-migration-source", "validate-prompt-block-rendering"].includes(operation)) return { operation, valid: true, validation: validateGraph(value), file: input2 };
1781
+ if (operation === "mermaid" || operation === "emit-mapping-mermaid") {
1782
+ const nodes = graphNodes(value), edges = graphEdges(value);
1783
+ const lines = ["flowchart TD", ...nodes.map((node) => ` ${String(node.id ?? node.nodeId)}[${String(node.name ?? node.type ?? "node")}]`), ...edges.map((edge) => ` ${String(edge.source ?? edge.from)} --> ${String(edge.target ?? edge.to)}`)];
1784
+ const out2 = option(args, "--out-file");
1785
+ if (out2) await writeFileText(out2, lines.join("\n"));
1786
+ return { mermaid: lines.join("\n"), output: out2 };
1787
+ }
1788
+ return { operation, input: input2, nodeCount: graphNodes(value).length, edgeCount: graphEdges(value).length, value };
1789
+ }
1790
+ const input = option(args, "--cases-file") ?? option(args, "--input");
1791
+ const cases = input ? await readJson3(input) : [{ id: option(args, "--synthetic-case-id") ?? "synthetic_smoke", message: "status" }];
1792
+ const rows = Array.isArray(cases) ? cases : [cases];
1793
+ const output = { cases: rows, executed: flag(args, "--execute"), results: [] };
1794
+ const out = option(args, "--out-json");
1795
+ if (out) await writeJson3(out, output);
1796
+ const html = option(args, "--out-html");
1797
+ if (html) await writeHtml(html, "Replay comparison", `<pre>${htmlEscape(safeJson(output))}</pre>`);
1798
+ return output;
1799
+ }
1800
+ async function writeFileText(file, content) {
1801
+ await ensureParent(file);
1802
+ const { writeFile: writeFile3 } = await import("fs/promises");
1803
+ await writeFile3(file, `${content}
1804
+ `, "utf8");
1805
+ }
1806
+
1807
+ // src/workflows/tester.ts
1808
+ import { join as join6 } from "path";
1809
+ import ExcelJS2 from "exceljs";
1810
+ async function casesFrom(file) {
1811
+ if (file.endsWith(".json")) return asRows(await readJson3(file));
1812
+ const workbook = new ExcelJS2.Workbook();
1813
+ await workbook.xlsx.readFile(file);
1814
+ const sheet = workbook.worksheets[0];
1815
+ if (!sheet) throw new Error("cases workbook has no worksheet");
1816
+ const headers = sheet.getRow(1).values.slice(1).map((v) => String(v ?? ""));
1817
+ const rows = [];
1818
+ sheet.eachRow((row, number) => {
1819
+ if (number === 1) return;
1820
+ const values = row.values.slice(1), item = {};
1821
+ headers.forEach((header, index) => {
1822
+ if (header) item[header] = values[index] ?? "";
1823
+ });
1824
+ rows.push(item);
1825
+ });
1826
+ return rows;
1827
+ }
1828
+ async function createSheet(args) {
1829
+ const cases = option(args, "--cases-file") ? await casesFrom(option(args, "--cases-file")) : [];
1830
+ const output = option(args, "--output") ?? join6(outputRoot("agent-tester"), `cases_${Date.now()}.xlsx`);
1831
+ await ensureParent(output);
1832
+ const workbook = new ExcelJS2.Workbook();
1833
+ const sheet = workbook.addWorksheet("cases");
1834
+ const headers = cases.length ? [...new Set(cases.flatMap((row) => Object.keys(row)))] : ["question", "expected_answer"];
1835
+ sheet.addRow(headers);
1836
+ cases.forEach((row) => sheet.addRow(headers.map((header) => row[header] ?? "")));
1837
+ await workbook.xlsx.writeFile(output);
1838
+ return { output, count: cases.length, mode: option(args, "--mode") };
1839
+ }
1840
+ async function submit(client, args) {
1841
+ const file = option(args, "--file", true);
1842
+ const result = await client.rawCall("POST", `/api_v2/gpt/label/project/${await client.projectId()}/uploadMessage`, { file, type: option(args, "--mode", true), ...option(args, "--agent-id") ? { agentId: Number(option(args, "--agent-id")) } : {}, ...option(args, "--flow-version") ? { flowVersion: Number(option(args, "--flow-version")) } : {} });
1843
+ return result;
1844
+ }
1845
+ async function runAgentTester(session, action2, args) {
1846
+ if (!action2) throw new Error("agent-tester action is required");
1847
+ if (action2 === "create-sheet") return createSheet(args);
1848
+ if (!session) throw new Error(`${action2} requires an authenticated tenant`);
1849
+ const client = new SolveaClient(session);
1850
+ if (action2 === "submit") return submit(client, args);
1851
+ if (action2 === "get-tasks") return client.rawCall("POST", `/api_v2/gpt/label/project/${await client.projectId()}/getLabelTask`, { page: intOption(args, "--page", 1), pageSize: intOption(args, "--page-size", 20), taskType: option(args, "--mode") });
1852
+ throw new Error(`unknown agent-tester action: ${action2}`);
1853
+ }
1854
+
1855
+ // src/workflows/delivery.ts
1856
+ import { join as join7 } from "path";
1857
+ import ExcelJS3 from "exceljs";
1858
+ var KNOWN_INTENTS = ["Product Recommendation", "Discount Inquiry", "Price Inquiry", "Stock Availability", "Payment Issues", "Request Invoice", "Modify Order", "Check Order Status", "Cancel Order", "Track Shipment", "Shipping Exception", "Missing Items", "Wrong Items Received", "Damaged Package", "Product Usage", "Return and exchange"];
1859
+ async function loadRows(file) {
1860
+ if (file.endsWith(".json")) {
1861
+ const value = await readJson3(file);
1862
+ return asRows(value);
1863
+ }
1864
+ const workbook = new ExcelJS3.Workbook();
1865
+ await workbook.xlsx.readFile(file);
1866
+ const sheet = workbook.worksheets[0];
1867
+ if (!sheet) throw new Error("input workbook has no worksheet");
1868
+ const headers = sheet.getRow(1).values.slice(1).map((v) => String(v ?? ""));
1869
+ const rows = [];
1870
+ sheet.eachRow((row, number) => {
1871
+ if (number === 1) return;
1872
+ const values = row.values.slice(1), item = {};
1873
+ headers.forEach((header, index) => {
1874
+ if (header) item[header] = values[index] ?? "";
1875
+ });
1876
+ rows.push(item);
1877
+ });
1878
+ return rows;
1879
+ }
1880
+ async function writeRows(file, rows) {
1881
+ if (file.endsWith(".json")) {
1882
+ await writeJson3(file, rows);
1883
+ return;
1884
+ }
1885
+ const workbook = new ExcelJS3.Workbook();
1886
+ const sheet = workbook.addWorksheet("results");
1887
+ const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
1888
+ sheet.addRow(keys);
1889
+ rows.forEach((row) => sheet.addRow(keys.map((key) => row[key] ?? "")));
1890
+ await ensureDir(join7(file, ".."));
1891
+ await workbook.xlsx.writeFile(file);
1892
+ }
1893
+ function classify(text) {
1894
+ const lower = text.toLowerCase();
1895
+ return KNOWN_INTENTS.find((intent) => lower.includes(intent.toLowerCase())) ?? (lower.includes("price") ? "Price Inquiry" : lower.includes("order") ? "Order Issues" : "New Intent");
1896
+ }
1897
+ async function classifyCases(args, domain) {
1898
+ const input = option(args, "--xlsx") ?? option(args, "--input");
1899
+ const noExcel = flag(args, "--no-excel");
1900
+ if (!input && !noExcel) throw new Error("--xlsx/--input or --no-excel is required");
1901
+ const rows = input ? await loadRows(input) : [];
1902
+ const grouped = /* @__PURE__ */ new Map();
1903
+ for (const row of rows) {
1904
+ const text = Object.values(row).join(" ");
1905
+ const intent = classify(text);
1906
+ grouped.set(intent, [...grouped.get(intent) ?? [], { ...row, intent }]);
1907
+ }
1908
+ const intents = [...grouped.entries()].map(([name, items]) => ({ name, definition: `Customer requests and issues related to ${name}.`, count: items.length, pct: rows.length ? items.length / rows.length : 0, samples: items.slice(0, 5), is_new: name === "New Intent" }));
1909
+ const runId = option(args, "--run-id") ?? Date.now().toString();
1910
+ const result = { meta: { run_id: runId, total: rows.length, classified: rows.length, mode: noExcel ? "no-excel" : "structured", domain }, intents, new_intents: intents.filter((item) => item.is_new) };
1911
+ const out = option(args, "--results") ?? join7(outputRoot(domain), `results_${runId}.json`);
1912
+ await writeJson3(out, result);
1913
+ await writeJson3(join7(stateRoot(domain), "progress.json"), { status: "classified", run_id: runId, results_path: out, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1914
+ return { ...result.meta, resultsPath: out };
1915
+ }
1916
+ async function plan(domain, args) {
1917
+ const file = join7(stateRoot(domain), "progress.json");
1918
+ let current = {};
1919
+ try {
1920
+ current = await readJson3(file);
1921
+ } catch {
1922
+ }
1923
+ if (flag(args, "--init") || !Object.keys(current).length) current = { status: "initialized", tenant: option(args, "--tenant"), brandName: option(args, "--brand-name"), brandWebsite: option(args, "--brand-website"), updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
1924
+ const status = option(args, "--status");
1925
+ if (status) current.status = status;
1926
+ const assignments = [];
1927
+ for (let index = 0; index < args.length; index += 1) {
1928
+ if (args[index] === "--set" && args[index + 1]) assignments.push(args[++index]);
1929
+ else if (args[index].startsWith("--set=")) assignments.push(args[index].slice(6));
1930
+ }
1931
+ for (const assignment of assignments) {
1932
+ const [key, ...value] = assignment.split("=");
1933
+ if (key) current[key] = value.join("=");
1934
+ }
1935
+ await writeJson3(file, current);
1936
+ return current;
1937
+ }
1938
+ async function runBatch(client, args, domain) {
1939
+ const input = option(args, "--input") ?? option(args, "--test-file", true);
1940
+ const rows = await loadRows(input);
1941
+ const output = option(args, "--output") ?? join7(outputRoot(domain), `test_results_${Date.now()}.json`);
1942
+ const workers = Math.max(1, Math.min(intOption(args, "--workers", 4), 16));
1943
+ const results = [];
1944
+ let cursor = 0;
1945
+ async function worker() {
1946
+ while (true) {
1947
+ const index = cursor++;
1948
+ if (index >= rows.length) return;
1949
+ const row = rows[index];
1950
+ const message = String(row.message ?? row.question ?? row.input ?? Object.values(row).join(" "));
305
1951
  try {
306
- const s = await loadSession();
307
- return print({ ok: true, loggedIn: true, email: s.email, channel: s.channel, accessExpiresAt: s.accessExpiry });
308
- } catch {
309
- return print({ ok: true, loggedIn: false });
1952
+ const response = await client.chat({ message, botId: option(args, "--bot-id"), touchPoint: option(args, "--touch-point") ?? "LIVE_CHAT", chatId: row.chatId });
1953
+ results[index] = { ...row, index, ok: true, message, response };
1954
+ } catch (error) {
1955
+ results[index] = { ...row, index, ok: false, message, error: error instanceof Error ? error.message : String(error) };
310
1956
  }
311
1957
  }
312
- if (action === "refresh") {
313
- const s = await authenticated();
314
- return print({ ok: true, accessExpiresAt: s.accessExpiry });
1958
+ }
1959
+ await Promise.all(Array.from({ length: workers }, () => worker()));
1960
+ await writeJson3(output, { meta: { total: rows.length, workers, domain, generatedAt: (/* @__PURE__ */ new Date()).toISOString() }, results });
1961
+ if (flag(args, "--report")) console.log(`completed ${results.filter((row) => row.ok).length}/${results.length} cases`);
1962
+ return { output, total: results.length, succeeded: results.filter((row) => row.ok).length, failed: results.filter((row) => !row.ok).length };
1963
+ }
1964
+ async function createAgents(client, args, domain) {
1965
+ const state2 = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
1966
+ const resultsPath = option(args, "--results") ?? (typeof state2.results_path === "string" ? state2.results_path : void 0);
1967
+ if (!resultsPath) throw new Error("classification results are required");
1968
+ const result = await readJson3(resultsPath);
1969
+ const intents = Array.isArray(result.intents) ? result.intents : [];
1970
+ if (flag(args, "--dry-run")) return { dryRun: true, intents: intents.map((item) => item.name) };
1971
+ const created = [];
1972
+ for (const intent of intents.filter((item) => Number(item.count ?? 0) > 0)) created.push(await client.createAgent({ name: `${String(intent.name)} ${domain === "poc" ? "POC" : "Delivery"}`, type: "CHAT_FLOW", meta: { intent: intent.name } }));
1973
+ return { created, count: created.length };
1974
+ }
1975
+ async function renderReport(args, domain) {
1976
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
1977
+ const resultsFile = option(args, "--results") ?? option(args, "--input") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
1978
+ if (!resultsFile) throw new Error("--results/--input is required, or run classify first");
1979
+ const value = await readJson3(resultsFile);
1980
+ const rows = asRows(value.results ?? value.items ?? value);
1981
+ const output = option(args, "--html") ?? option(args, "--output") ?? join7(outputRoot(domain), `${domain}_report.html`);
1982
+ const body = `<p>Total: ${rows.length}</p>${rows.map((row, index) => `<div class="card"><h2>${index + 1}. ${htmlEscape(row.intent ?? row.question ?? row.message ?? "Case")}</h2><pre>${htmlEscape(JSON.stringify(row, null, 2))}</pre></div>`).join("")}`;
1983
+ await writeHtml(output, option(args, "--title") ?? `${domain} report`, body);
1984
+ const md = option(args, "--md");
1985
+ if (md) await import("fs/promises").then((fs3) => fs3.writeFile(md, `# ${domain} report
1986
+
1987
+ Total: ${rows.length}
1988
+ `, "utf8"));
1989
+ return { output, count: rows.length };
1990
+ }
1991
+ async function genExcel(args, domain) {
1992
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
1993
+ const input = option(args, "--results") ?? option(args, "--items") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
1994
+ if (!input) throw new Error("--results or --items is required, or run classify first");
1995
+ const value = await readJson3(input);
1996
+ const rows = asRows(value);
1997
+ const output = option(args, "--output") ?? join7(outputRoot(domain), `${domain}_results.xlsx`);
1998
+ await writeRows(output, rows);
1999
+ return { output, count: rows.length };
2000
+ }
2001
+ async function sampleHistory(client, args) {
2002
+ const output = option(args, "--output", true);
2003
+ const result = await client.listTranscripts({ pageIndex: 1, pageSize: intOption(args, "--max-conversations", 50), debug: false });
2004
+ const rows = asRows(result).slice(0, intOption(args, "--total", 100));
2005
+ await writeJson3(output, rows.map((row, index) => ({ id: row.chatId ?? row.id ?? String(index), message: row.message ?? row.lastMessage ?? "", metadata: flag(args, "--with-metadata") ? row : void 0 })));
2006
+ return { output, count: rows.length };
2007
+ }
2008
+ async function inspectChatflow(client, args) {
2009
+ const ids = args.flatMap((value, index) => value === "--agent-id" ? [args[index + 1]] : []).filter(Boolean);
2010
+ const results = [];
2011
+ for (const id of ids) results.push({ agentId: id, graph: await client.getChatflowGraph(id) });
2012
+ return results;
2013
+ }
2014
+ async function runDelivery(session, action2, args) {
2015
+ return runDomain(session, "delivery", action2, args);
2016
+ }
2017
+ async function runPoc(session, action2, args) {
2018
+ return runDomain(session, "poc", action2, args);
2019
+ }
2020
+ async function runDomain(session, domain, action2, args) {
2021
+ if (!action2) throw new Error(`${domain} action is required`);
2022
+ if (action2 === "classify") return classifyCases(args, domain);
2023
+ if (action2 === "plan") return plan(domain, args);
2024
+ if (action2 === "report" || action2 === "render" || action2 === "render-report" || action2 === "manual") return renderReport(args, domain);
2025
+ if (action2 === "excel" || action2 === "gen-excel") return genExcel(args, domain);
2026
+ if (!session) throw new Error(`${domain} ${action2} requires an authenticated tenant`);
2027
+ const client = new SolveaClient(session);
2028
+ if (action2 === "batch-test" || action2 === "test") return runBatch(client, args, domain);
2029
+ if (action2 === "create-agents") return createAgents(client, args, domain);
2030
+ if (action2 === "sample-history") return sampleHistory(client, args);
2031
+ if (action2 === "inspect-chatflow") return inspectChatflow(client, args);
2032
+ if (action2 === "render-summary") return plan(domain, args);
2033
+ throw new Error(`unknown ${domain} action: ${action2}`);
2034
+ }
2035
+
2036
+ // src/workflows/kb-builder.ts
2037
+ import { join as join8 } from "path";
2038
+ import ExcelJS4 from "exceljs";
2039
+ var clean = (value) => String(value ?? "").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
2040
+ var absolute = (href, base) => {
2041
+ try {
2042
+ return new URL(href, base).toString();
2043
+ } catch {
2044
+ return void 0;
2045
+ }
2046
+ };
2047
+ async function crawl(args) {
2048
+ const url = option(args, "--url", true);
2049
+ const maxPages = intOption(args, "--max-pages", 50), maxDepth = intOption(args, "--max-depth", 2), timeout = intOption(args, "--timeout", 20) * 1e3;
2050
+ const origin = new URL(url).origin, queue = [{ url, depth: 0 }], seen = /* @__PURE__ */ new Set(), pages = [];
2051
+ while (queue.length && pages.length < maxPages) {
2052
+ const current = queue.shift();
2053
+ if (seen.has(current.url) || current.depth > maxDepth) continue;
2054
+ seen.add(current.url);
2055
+ try {
2056
+ const response = await fetch(current.url, { signal: AbortSignal.timeout(timeout), headers: { accept: "text/html,application/xhtml+xml" } });
2057
+ if (!response.ok) continue;
2058
+ const html = await response.text();
2059
+ const title = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i)?.[1] ?? "";
2060
+ const text = clean(html);
2061
+ pages.push({ url: current.url, depth: current.depth, title: clean(title), text: text.slice(0, 5e4), status: response.status });
2062
+ if (current.depth < maxDepth) for (const match of html.matchAll(/href\s*=\s*["']([^"']+)["']/gi)) {
2063
+ const next = absolute(match[1], current.url);
2064
+ if (next && next.startsWith(origin) && !seen.has(next)) queue.push({ url: next, depth: current.depth + 1 });
2065
+ }
2066
+ } catch (error) {
2067
+ pages.push({ url: current.url, depth: current.depth, error: error instanceof Error ? error.message : String(error) });
315
2068
  }
316
2069
  }
317
- if (command === "tenant" || command === "context") {
318
- const session = await authenticated();
319
- if (sub === "current") return print(publicTenant(session.tenant));
320
- if (sub === "clear") {
321
- delete session.tenant;
322
- await saveSession(session);
323
- return print({ ok: true, cleared: true });
2070
+ const result = { url, mode: option(args, "--mode") ?? "auto", pages, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), total: pages.length };
2071
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "crawl_result.json");
2072
+ await writeJson3(output, result);
2073
+ return { ...result, output };
2074
+ }
2075
+ async function directoryPlan(args) {
2076
+ const source = await readJson3(option(args, "--crawl-result", true));
2077
+ const rows = asRows(source.pages ?? source);
2078
+ const groups = /* @__PURE__ */ new Map();
2079
+ for (const page2 of rows) {
2080
+ const title = String(page2.title ?? page2.url ?? "Untitled");
2081
+ const key = title.split(/[:|/\\-]/)[0].trim() || "General";
2082
+ groups.set(key, [...groups.get(key) ?? [], page2]);
2083
+ }
2084
+ const tree = [...groups.entries()].map(([name, pages]) => ({ name, children: pages.slice(0, 100).map((page2) => ({ name: String(page2.title ?? page2.url), sourceUrl: page2.url })) }));
2085
+ const result = { source: option(args, "--crawl-result"), generatedAt: (/* @__PURE__ */ new Date()).toISOString(), tree, confirmed: false };
2086
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "directory_plan.json");
2087
+ await writeJson3(output, result);
2088
+ if (flag(args, "--write-confirmed-tree")) await writeJson3(join8(stateRoot("kb-builder"), "confirmed_tree.json"), { ...result, confirmed: true });
2089
+ return { output, directories: tree.length, pages: rows.length, tree };
2090
+ }
2091
+ async function createDirectories(client, args) {
2092
+ const file = option(args, "--tree-file") ?? join8(stateRoot("kb-builder"), "confirmed_tree.json");
2093
+ const value = await readJson3(file);
2094
+ const tree = Array.isArray(value.tree) ? value.tree : Array.isArray(value) ? value : [];
2095
+ if (!tree.length) throw new Error("confirmed directory tree is empty");
2096
+ const dryRun = flag(args, "--dry-run"), created = [];
2097
+ async function visit(nodes, parentId = 0, depth = 0) {
2098
+ if (depth > intOption(args, "--max-depth", 3)) throw new Error("directory tree exceeds max depth");
2099
+ for (const node of nodes) {
2100
+ const name = String(node.name ?? "").trim();
2101
+ if (!name) continue;
2102
+ const result = dryRun ? { name, parentId, dryRun: true } : await client.createFolder(name, parentId);
2103
+ created.push(result);
2104
+ const id = Number(result?.id ?? result?.directoryId ?? 0);
2105
+ const children = Array.isArray(node.children) ? node.children : [];
2106
+ if (children.length && id) await visit(children, id, depth + 1);
324
2107
  }
325
- if (sub === "search") return print(await search(session, positionals(rest)[0] ?? "", option(rest, "--env", true)));
326
- if (sub === "use") return print(await useTenant(session, Number(positionals(rest)[0]), option(rest, "--env", true), option(rest, "--purpose", true)));
327
2108
  }
328
- if (command === "api") {
2109
+ await visit(tree);
2110
+ return { file, dryRun, created, count: created.length };
2111
+ }
2112
+ async function extractWebQa(args) {
2113
+ const input = await readJson3(option(args, "--crawl-result", true));
2114
+ const pages = asRows(input.pages ?? input).slice(0, intOption(args, "--max-pages", 80));
2115
+ const outputDir2 = option(args, "--output-dir") ?? join8(outputRoot("kb-builder"), "qa_parts");
2116
+ await ensureDir(outputDir2);
2117
+ const parts = pages.map((page2, index) => ({ question: String(page2.title ?? page2.url), answer: String(page2.text ?? "").slice(0, intOption(args, "--answer-limit", 3500)), sourceUrl: page2.url, sourceTitle: page2.title, index }));
2118
+ const files = [];
2119
+ for (const [index, part] of parts.entries()) {
2120
+ const file = join8(outputDir2, `part_${String(index + 1).padStart(4, "0")}.json`);
2121
+ await writeJson3(file, { items: [part] });
2122
+ files.push(file);
2123
+ }
2124
+ return { outputDir: outputDir2, files, count: files.length };
2125
+ }
2126
+ async function importQa(client, args) {
2127
+ const qaFile = option(args, "--qa-file");
2128
+ const fromDir = option(args, "--from-dir");
2129
+ if (!qaFile && !fromDir) throw new Error("--qa-file or --from-dir is required");
2130
+ const items = [];
2131
+ if (qaFile) {
2132
+ const value = await readJson3(qaFile);
2133
+ items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2134
+ }
2135
+ if (fromDir) {
2136
+ const { readdir } = await import("fs/promises");
2137
+ for (const file of (await readdir(fromDir)).filter((name) => name.endsWith(".json"))) {
2138
+ const value = await readJson3(join8(fromDir, file));
2139
+ items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2140
+ }
2141
+ }
2142
+ const plan2 = { items, count: items.length, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
2143
+ const planFile = join8(outputRoot("kb-builder"), `qa_import_plan_${Date.now()}.json`);
2144
+ await writeJson3(planFile, plan2);
2145
+ if (flag(args, "--dry-run")) return { dryRun: true, planFile, count: items.length };
2146
+ return { planFile, count: items.length, result: await client.uploadQa(items) };
2147
+ }
2148
+ async function importSources(client, args) {
2149
+ const plan2 = await readJson3(option(args, "--plan-file", true));
2150
+ const documents = Array.isArray(plan2.documents) ? plan2.documents : Array.isArray(plan2.items) ? plan2.items : [];
2151
+ const payload = { documents, taskType: "WEB", published: true, isVisible: true, metadata: { tags: [] }, directoryId: String(plan2.directoryId ?? "") };
2152
+ if (!flag(args, "--execute")) return { dryRun: true, payload };
2153
+ return client.rawCall("POST", `${client.qamPath}/project/${await client.projectId()}/documents`, payload);
2154
+ }
2155
+ async function importTemplates(client, args) {
2156
+ const source = option(args, "--plan-file") ?? option(args, "--xlsx");
2157
+ if (!source) throw new Error("--xlsx or --plan-file is required");
2158
+ const rows = [];
2159
+ if (source.endsWith(".json")) rows.push(...asRows(await readJson3(source)));
2160
+ else {
2161
+ const workbook = new ExcelJS4.Workbook();
2162
+ await workbook.xlsx.readFile(source);
2163
+ const sheet = option(args, "--sheet") ? workbook.getWorksheet(option(args, "--sheet")) : workbook.worksheets[0];
2164
+ if (!sheet) throw new Error("workbook has no worksheet");
2165
+ const headers = sheet.getRow(1).values.slice(1).map((v) => String(v ?? ""));
2166
+ sheet.eachRow((row, number) => {
2167
+ if (number === 1) return;
2168
+ const values = row.values.slice(1);
2169
+ const item = {};
2170
+ headers.forEach((header, index) => {
2171
+ if (header) item[header] = values[index] ?? "";
2172
+ });
2173
+ rows.push(item);
2174
+ });
2175
+ }
2176
+ const items = rows.map((row) => ({ name: String(row.name ?? row.Name ?? "").trim(), content: String(row.content ?? row.Content ?? row.template ?? ""), status: row.status ?? row.Status ?? "ENABLED", scene: row.scene ?? row.Scene })).filter((item) => item.name && item.content);
2177
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `template_import_plan_${Date.now()}.json`);
2178
+ await writeJson3(output, { items, count: items.length });
2179
+ if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
2180
+ const results = [];
2181
+ for (const item of items) results.push(await client.createTemplate(item));
2182
+ return { output, count: results.length, results };
2183
+ }
2184
+ async function exportKnowledge(client, args) {
2185
+ const directories = asRows(await client.listDirectories());
2186
+ const ids = option(args, "--directory-id") ? [Number(option(args, "--directory-id"))] : directories.map((row) => Number(row.id ?? row.directoryId)).filter(Number.isFinite);
2187
+ const rows = [];
2188
+ for (const id of ids) {
2189
+ const value = await client.listKnowledge({ directoryId: id, keyword: option(args, "--keyword") ?? "", type: option(args, "--type") ?? "ALL", pageSize: intOption(args, "--page-size", 1e3) });
2190
+ rows.push(...asRows(value).map((row) => ({ ...row, directoryId: id, directoryName: directories.find((dir) => Number(dir.id ?? dir.directoryId) === id)?.name ?? "" })));
2191
+ }
2192
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `knowledge_${Date.now()}.xlsx`);
2193
+ const workbook = new ExcelJS4.Workbook();
2194
+ const sheet = workbook.addWorksheet("knowledge");
2195
+ const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2196
+ sheet.addRow(keys);
2197
+ for (const row of rows) sheet.addRow(keys.map((key) => row[key] ?? ""));
2198
+ await ensureDir(join8(output, ".."));
2199
+ await workbook.xlsx.writeFile(output);
2200
+ return { output, count: rows.length };
2201
+ }
2202
+ async function runKbBuilder(session, action2, args) {
2203
+ if (!action2) throw new Error("kb-builder action is required");
2204
+ if (action2 === "crawl") return crawl(args);
2205
+ if (action2 === "directory-plan") return directoryPlan(args);
2206
+ if (!session) throw new Error(`${action2} requires an authenticated tenant`);
2207
+ const client = new SolveaClient(session);
2208
+ if (action2 === "create-directories") return createDirectories(client, args);
2209
+ if (action2 === "extract-web-qa") return extractWebQa(args);
2210
+ if (action2 === "import-qa") return importQa(client, args);
2211
+ if (action2 === "import-source-documents") return importSources(client, args);
2212
+ if (action2 === "import-templates") return importTemplates(client, args);
2213
+ if (action2 === "export-knowledge") return exportKnowledge(client, args);
2214
+ if (action2 === "extract-ticket-qa" || action2 === "batch-extract-ticket-qa") return extractTicketQa(args);
2215
+ throw new Error(`unknown kb-builder action: ${action2}`);
2216
+ }
2217
+ async function extractTicketQa(args) {
2218
+ const file = option(args, "--xlsx", true);
2219
+ const workbook = new ExcelJS4.Workbook();
2220
+ await workbook.xlsx.readFile(file);
2221
+ const sheet = workbook.worksheets[0];
2222
+ if (!sheet) throw new Error("workbook has no worksheet");
2223
+ const headers = sheet.getRow(1).values.slice(1).map((v) => String(v ?? ""));
2224
+ const messageCol = option(args, "--messages-col") ?? headers.find((header) => /message|conversation|content|描述/i.test(header)) ?? headers[0];
2225
+ const titleCol = option(args, "--title-col");
2226
+ const replyCol = option(args, "--reply-col");
2227
+ const brand = option(args, "--brand", true);
2228
+ const items = [];
2229
+ sheet.eachRow((row, number) => {
2230
+ if (number === 1) return;
2231
+ const values = row.values.slice(1), record = {};
2232
+ headers.forEach((header, index) => {
2233
+ record[header] = values[index] ?? "";
2234
+ });
2235
+ const question = `${brand}: ${String(record[titleCol] ?? "").trim()} ${String(record[messageCol] ?? "").trim()}`.trim();
2236
+ const answer = String(record[replyCol] ?? "").trim();
2237
+ if (question && question !== `${brand}:`) items.push({ question, answer, sourceRow: number });
2238
+ });
2239
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `ticket_qa_${Date.now()}.json`);
2240
+ const result = { brand, count: items.length, items };
2241
+ await writeJson3(output, result);
2242
+ if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
2243
+ return { output, count: items.length, items };
2244
+ }
2245
+
2246
+ // src/workflows/desk.ts
2247
+ import { join as join9 } from "path";
2248
+ import ExcelJS5 from "exceljs";
2249
+ var taskId = (args) => option(args, "--task-id") ?? (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
2250
+ var taskDir = (args) => join9(stateRoot("solvea-desk"), taskId(args));
2251
+ async function saveDatasource(dir, name, rows) {
2252
+ const file = join9(dir, name);
2253
+ await ensureParent(file);
2254
+ const workbook = new ExcelJS5.Workbook();
2255
+ const sheet = workbook.addWorksheet("data");
2256
+ const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2257
+ sheet.addRow(keys);
2258
+ for (const row of rows) sheet.addRow(keys.map((key) => row[key] ?? ""));
2259
+ await workbook.xlsx.writeFile(file);
2260
+ return file;
2261
+ }
2262
+ async function fetchTickets(client, args) {
2263
+ const dir = taskDir(args);
2264
+ const pageSize2 = Math.max(1, Math.min(intOption(args, "--page-size", 100), 500));
2265
+ const maxPages = intOption(args, "--max-pages", 100);
2266
+ const maxRows = intOption(args, "--max-rows", 1e4);
2267
+ const rows = [];
2268
+ for (let page2 = 1; page2 <= maxPages && rows.length < maxRows; page2 += 1) {
2269
+ const value = await client.rawCall("POST", "/api_v2/tars/api/ticket/list", { viewId: option(args, "--view-id") ?? "1", page: page2, pageSize: pageSize2, sort: option(args, "--sort") ?? "last_update_time", order: option(args, "--order") ?? "DESC", ...option(args, "--filters-file") ? await readJson3(option(args, "--filters-file")) : {} });
2270
+ const pageRows = asRows(value);
2271
+ rows.push(...pageRows.slice(0, maxRows - rows.length));
2272
+ if (pageRows.length < pageSize2) break;
2273
+ }
2274
+ const output = await saveDatasource(dir, "datasource.xlsx", rows);
2275
+ await writeJson3(join9(dir, "metadata.json"), { taskId: taskId(args), rows: rows.length, output });
2276
+ return { taskId: taskId(args), output, count: rows.length };
2277
+ }
2278
+ async function fetchSources(client, args) {
2279
+ const dir = taskDir(args);
2280
+ const begin = option(args, "--start", true), end = option(args, "--end", true);
2281
+ const sources = { begin, end, tickets: [] };
2282
+ const value = await client.rawCall("POST", "/api_v2/tars/api/ticket/list", { startTime: begin, endTime: end, page: 1, pageSize: intOption(args, "--max-rows", 1e4) });
2283
+ const rows = asRows(value).slice(0, intOption(args, "--max-rows", 1e4));
2284
+ sources.tickets = rows;
2285
+ const output = await saveDatasource(dir, "datasource.xlsx", rows);
2286
+ await writeJson3(join9(dir, "sources.json"), sources);
2287
+ return { taskId: taskId(args), output, count: rows.length };
2288
+ }
2289
+ async function tags(client, action2, args) {
2290
+ if (action2 === "list-tags") return client.rawCall("GET", "/api_v2/tars/api/ticket/tag/tree");
2291
+ const ticket = option(args, "--ticket-number", true);
2292
+ if (action2 === "get-ticket-tags") return client.rawCall("GET", `/api_v2/tars/api/ticket/${encodeURIComponent(ticket)}/tags`);
2293
+ if (action2 === "search-tags") {
2294
+ const tree = await client.rawCall("GET", "/api_v2/tars/api/ticket/tag/tree");
2295
+ const needle = option(args, "--name", true).toLowerCase();
2296
+ const flatten = (value) => Array.isArray(value) ? value.flatMap(flatten) : value && typeof value === "object" ? [value, ...flatten(value.children ?? value.nodes ?? [])] : [];
2297
+ return flatten(tree).filter((row) => String(row.name ?? row.label ?? "").toLowerCase().includes(needle));
2298
+ }
2299
+ if (action2 === "batch-get-ticket-tags") {
2300
+ const ids = asRows(await readJson3(option(args, "--ticket-ids-file", true)));
2301
+ const result = [];
2302
+ for (const row of ids) result.push({ ...row, tags: await client.rawCall("GET", `/api_v2/tars/api/ticket/${encodeURIComponent(String(row.ticketNumber ?? row.ticketId ?? row.id))}/tags`) });
2303
+ return result;
2304
+ }
2305
+ if (action2 === "bind-tags" || action2 === "replace-tags") {
2306
+ if (!flag(args, "--confirm")) throw new Error(`${action2} requires --confirm`);
2307
+ const tagsFile = option(args, "--tags-file", true);
2308
+ return client.rawCall("POST", `/api_v2/tars/api/ticket/${encodeURIComponent(ticket)}/tags`, { tags: await readJson3(tagsFile) });
2309
+ }
2310
+ throw new Error(`unknown tag action: ${action2}`);
2311
+ }
2312
+ async function renderReport2(args) {
2313
+ const dir = taskDir(args), dataFile = option(args, "--report-data") ?? join9(dir, "report_data.json"), notesFile = option(args, "--notes") ?? join9(dir, "calculation_notes.json");
2314
+ const data3 = await readJson3(dataFile);
2315
+ if (flag(args, "--validate-only")) return { valid: true, dataFile };
2316
+ const output = option(args, "--output") ?? join9(outputRoot("solvea-desk"), taskId(args), `${option(args, "--report-slug") ?? "report"}.html`);
2317
+ const body = `<pre>${htmlEscape(JSON.stringify({ data: data3, notes: await readJson3(notesFile).catch(() => ({})) }, null, 2))}</pre>`;
2318
+ await writeHtml(output, option(args, "--report-slug") ?? "Solvea Desk report", body);
2319
+ return { output, valid: true };
2320
+ }
2321
+ async function runDesk(session, action2, args) {
2322
+ if (!action2) throw new Error("solvea-desk action is required");
2323
+ const client = new SolveaClient(session);
2324
+ if (action2 === "fetch-tickets") return fetchTickets(client, args);
2325
+ if (action2 === "fetch-sources") return fetchSources(client, args);
2326
+ if (action2 === "render-report") return renderReport2(args);
2327
+ if (action2 === "tags") return tags(client, option(args, "--operation") ?? args.find((value) => ["list-tags", "get-ticket-tags", "batch-get-ticket-tags", "search-tags", "bind-tags", "replace-tags"].includes(value)) ?? "list-tags", args);
2328
+ if (["list-tags", "get-ticket-tags", "batch-get-ticket-tags", "search-tags", "bind-tags", "replace-tags"].includes(action2)) return tags(client, action2, args);
2329
+ throw new Error(`unknown solvea-desk action: ${action2}`);
2330
+ }
2331
+
2332
+ // src/cli.ts
2333
+ var print = (value) => console.log(JSON.stringify(value, null, 2));
2334
+ var usage = () => [
2335
+ "cxclawctl <resource> <action> [options]",
2336
+ "cxclawctl auth|tenant|sls|runtime|doctor|update|setup|version",
2337
+ "cxclawctl agent-builder|agent-tester|delivery|poc|kb-builder|solvea-desk <action>",
2338
+ resourceHelp(),
2339
+ "Example: cxclawctl intent create --data-file intent.json"
2340
+ ].join("\n\n");
2341
+ async function runAuth(action2, args) {
2342
+ if (action2 === "login") return print(await login(option(args, "--server", true), option(args, "--channel") ?? "stable"));
2343
+ if (action2 === "logout") {
2344
+ await logout();
2345
+ return print({ ok: true, loggedOut: true });
2346
+ }
2347
+ if (action2 === "status") {
2348
+ try {
2349
+ const session = await loadSession();
2350
+ return print({ ok: true, loggedIn: true, email: session.email, channel: session.channel, accessExpiresAt: session.accessExpiry });
2351
+ } catch {
2352
+ return print({ ok: true, loggedIn: false });
2353
+ }
2354
+ }
2355
+ if (action2 === "refresh") {
329
2356
  const session = await authenticated();
330
- if (!sub) throw new Error("api command is required");
331
- await runApi(session, sub, rest);
2357
+ return print({ ok: true, accessExpiresAt: session.accessExpiry });
2358
+ }
2359
+ throw new Error("auth action must be login, logout, status, or refresh");
2360
+ }
2361
+ async function runTenant(action2, args) {
2362
+ const session = await authenticated();
2363
+ if (action2 === "current") return print(publicTenant(session.tenant));
2364
+ if (action2 === "clear") {
2365
+ delete session.tenant;
2366
+ await saveSession(session);
2367
+ return print({ ok: true, cleared: true });
2368
+ }
2369
+ if (action2 === "search") return print(await search(session, positionals(args)[0] ?? "", option(args, "--env", true)));
2370
+ if (action2 === "use") return print(await useTenant(session, Number(positionals(args)[0]), option(args, "--env", true), option(args, "--purpose", true)));
2371
+ throw new Error("tenant action must be search, use, current, or clear");
2372
+ }
2373
+ async function main(args = process.argv.slice(2)) {
2374
+ const [command, action2, ...rest] = args;
2375
+ if (!command || command === "help" || flag(args, "--help")) {
2376
+ console.log(command && isResourceCommand(command) ? resourceHelp(command, action2 && !["help", "--help"].includes(action2) ? action2 : void 0) : usage());
332
2377
  return;
333
2378
  }
334
- if (command === "script") {
335
- if (!sub) throw new Error("script path is required");
336
- process.exitCode = await runPython(sub, rest);
2379
+ if (isResourceCommand(command)) {
2380
+ await runResourceCommand(await authenticated(), command, action2, rest);
337
2381
  return;
338
2382
  }
339
- if (command === "sls" && sub === "query") {
340
- const session = await authenticated();
341
- return print(await query(session, { from: Number(option(rest, "--from", true)), to: Number(option(rest, "--to", true)), query: option(rest, "--query", true), line: Number(option(rest, "--line") ?? 50), offset: Number(option(rest, "--offset") ?? 0), reverse: flag(rest, "--reverse") }));
2383
+ if (command === "version") {
2384
+ if (flag(args, "--json")) return print({ pluginVersion: process.env.CXCLAW_PLUGIN_VERSION ?? null, cliVersion: VERSION, toolSchemaVersion: TOOL_SCHEMA_VERSION, serverApiVersion: SERVER_API_VERSION });
2385
+ console.log(`cxclawctl ${VERSION}`);
2386
+ return;
342
2387
  }
343
- if (command === "doctor") {
344
- const manifest = JSON.parse(await readFile(new URL("../plugin.json", import.meta.url), "utf8"));
345
- if (manifest.version !== VERSION) throw new Error(`plugin version ${manifest.version} does not match CLI ${VERSION}`);
346
- return print({ ok: true, node: process.versions.node, cliVersion: VERSION, root: packageRoot() });
2388
+ if (command === "setup") {
2389
+ const channel = option(args, "--channel") ?? "stable";
2390
+ await installMarketplace(channel);
2391
+ await login(option(args, "--server", true), channel);
2392
+ await installScheduler();
2393
+ return;
347
2394
  }
2395
+ if (command === "auth") return runAuth(action2, rest);
2396
+ if (command === "login" || command === "logout") return runAuth(command, args.slice(1));
2397
+ if (command === "tenant" || command === "context") return runTenant(action2, rest);
2398
+ if (command === "runtime") return print(await runRuntime(action2, rest));
2399
+ if (command === "workflow") return print(await runSolveaKitWorkflow(action2, rest));
2400
+ if (command === "support") return print(await runSupport(await authenticated(), action2, rest));
2401
+ if (command === "agent-builder") return print(await runAgentBuilder(["validate", "compile", "merge-source", "validate-tool", "migration", "replay"].includes(action2 ?? "") ? void 0 : await authenticated(), action2, rest));
2402
+ if (command === "agent-tester") return print(await runAgentTester(action2 === "create-sheet" ? void 0 : await authenticated(), action2, rest));
2403
+ if (command === "delivery") return print(await runDelivery(["classify", "plan", "report", "render", "render-report", "excel", "gen-excel", "render-summary"].includes(action2 ?? "") ? void 0 : await authenticated(), action2, rest));
2404
+ if (command === "poc") return print(await runPoc(["classify", "plan", "report", "render", "render-report", "excel", "gen-excel", "manual", "render-summary"].includes(action2 ?? "") ? void 0 : await authenticated(), action2, rest));
2405
+ if (command === "kb-builder") return print(await runKbBuilder(["crawl", "directory-plan", "extract-web-qa", "extract-ticket-qa", "batch-extract-ticket-qa"].includes(action2 ?? "") ? void 0 : await authenticated(), action2, rest));
2406
+ if (command === "solvea-desk") return print(await runDesk(await authenticated(), action2, rest));
2407
+ if (command === "api") {
2408
+ if (!action2) throw new Error("api command is required");
2409
+ await runApi(await authenticated(), action2, rest);
2410
+ return;
2411
+ }
2412
+ if (command === "sls" && action2 === "query") {
2413
+ return print(await query(await authenticated(), {
2414
+ from: Number(option(rest, "--from", true)),
2415
+ to: Number(option(rest, "--to", true)),
2416
+ query: option(rest, "--query", true),
2417
+ line: Number(option(rest, "--line") ?? 50),
2418
+ offset: Number(option(rest, "--offset") ?? 0),
2419
+ reverse: flag(rest, "--reverse")
2420
+ }));
2421
+ }
2422
+ if (command === "doctor") return print(await diagnose());
348
2423
  if (command === "update") {
349
2424
  if (flag(args, "--install-scheduler")) {
350
2425
  await installScheduler();
351
- return;
2426
+ return print({ ok: true, schedulerInstalled: true });
352
2427
  }
353
- if (flag(args, "--scheduled")) await new Promise((r) => setTimeout(r, Math.random() * 18e5));
354
- return print({ version: await update() });
2428
+ if (flag(args, "--scheduled")) await new Promise((resolve5) => setTimeout(resolve5, Math.random() * 18e5));
2429
+ return print(await update());
355
2430
  }
356
- if (command === "commands" || command === "capabilities") return console.log(await readFile(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
357
- throw new Error(`unknown command: ${command}`);
2431
+ if (command === "commands" || command === "capabilities") console.log(await readFile5(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
2432
+ else throw new Error(`unknown command: ${command}`);
358
2433
  }
359
2434
  main().catch((error) => {
360
2435
  console.error(`cxclawctl: ${error instanceof Error ? error.message : String(error)}`);