@shulex/cxclawctl 0.1.11 → 0.1.13

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.
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 as readFile7 } from "fs/promises";
4
+ import { readFile as readFile6 } from "fs/promises";
5
5
 
6
6
  // src/auth.ts
7
7
  import open from "open";
@@ -12,7 +12,7 @@ var AUTH_SERVER_URL = "https://ai.solvea.cx/api_v2/ticket";
12
12
  // package.json
13
13
  var package_default = {
14
14
  name: "@shulex/cxclawctl",
15
- version: "0.1.11",
15
+ version: "0.1.13",
16
16
  description: "Solvea CXClaw CLI and Codex plugin runtime",
17
17
  type: "module",
18
18
  bin: {
@@ -22,7 +22,6 @@ var package_default = {
22
22
  "bin",
23
23
  "dist/cli.js",
24
24
  "dist/cli.js.map",
25
- "runtime",
26
25
  "capabilities.lock.json"
27
26
  ],
28
27
  scripts: {
@@ -75,9 +74,17 @@ var HttpError = class extends Error {
75
74
  this.status = status;
76
75
  this.responseBody = responseBody;
77
76
  this.name = "HttpError";
77
+ try {
78
+ const value = JSON.parse(responseBody);
79
+ const code = Number(value?.code);
80
+ this.responseCode = Number.isFinite(code) ? code : void 0;
81
+ } catch {
82
+ this.responseCode = void 0;
83
+ }
78
84
  }
79
85
  status;
80
86
  responseBody;
87
+ responseCode;
81
88
  };
82
89
  function unwrap(value) {
83
90
  if (value && typeof value === "object" && Object.keys(value).length === 1 && "data" in value) return value.data;
@@ -133,38 +140,47 @@ async function deleteSession() {
133
140
  await entry().deleteCredential();
134
141
  }
135
142
 
136
- // runtime/auth-wait-state.mjs
137
- import { createHash } from "crypto";
138
- import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises";
139
- import { tmpdir } from "os";
140
- import { join } from "path";
141
- var markerRoot = join(tmpdir(), "cxclaw-auth-wait");
142
- var markerTtlMs = 15 * 60 * 1e3;
143
- var markerName = (sessionId, pid) => `${createHash("sha256").update(sessionId).digest("hex").slice(0, 24)}-${pid}.json`;
144
- async function withAuthWaitMarker(operation, env = process.env) {
145
- const sessionId = env.CODEX_SESSION_ID ?? env.CODEX_THREAD_ID;
146
- if (!sessionId) return operation();
147
- await mkdir(markerRoot, { recursive: true, mode: 448 });
148
- const path = join(markerRoot, markerName(sessionId, process.pid));
149
- await writeFile(path, JSON.stringify({
150
- sessionId,
151
- threadId: env.CODEX_THREAD_ID ?? null,
152
- pid: process.pid,
153
- expiresAt: Date.now() + markerTtlMs
154
- }), { mode: 384 });
155
- try {
156
- return await operation();
157
- } finally {
158
- await rm(path, { force: true }).catch(() => void 0);
159
- }
143
+ // src/cli-error.ts
144
+ var CliError = class extends Error {
145
+ constructor(body) {
146
+ super(body.message);
147
+ this.body = body;
148
+ this.name = "CliError";
149
+ }
150
+ body;
151
+ };
152
+ function notAuthenticated(message = "CXClaw \u5C1A\u672A\u767B\u5F55") {
153
+ return new CliError({
154
+ code: 3,
155
+ category: "auth",
156
+ message,
157
+ reason: "not_authenticated",
158
+ retryable: false,
159
+ hint: "\u8FD0\u884C cxclawctl auth login \u5B8C\u6210\u9489\u9489\u6388\u6743",
160
+ actions: ["cxclawctl auth login"]
161
+ });
162
+ }
163
+ function errorOutput(error) {
164
+ if (error instanceof CliError) return { error: error.body };
165
+ return {
166
+ error: {
167
+ code: 1,
168
+ category: "internal",
169
+ message: error instanceof Error ? error.message : String(error),
170
+ reason: "command_failed",
171
+ retryable: false
172
+ }
173
+ };
160
174
  }
161
175
 
162
176
  // src/auth.ts
163
177
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
164
- var loginInFlight;
165
178
  function publicAuthStatus(session) {
166
179
  return { ok: true, loggedIn: true, email: session.email, channel: session.channel, accessExpiresAt: session.accessExpiry };
167
180
  }
181
+ function isAuthorizationPending(error) {
182
+ return error instanceof HttpError && (error.status === 428 || error.responseCode === 428);
183
+ }
168
184
  async function authorizeDevice(channel, runtime) {
169
185
  const session = { channel, accessToken: "", refreshToken: "", accessExpiry: 0, employeeId: "", email: "" };
170
186
  const start = await runtime.start(session);
@@ -184,10 +200,10 @@ ${start.verificationUriComplete}
184
200
  const token = await runtime.poll(session, start.deviceCode);
185
201
  Object.assign(session, { accessToken: token.accessToken, refreshToken: token.refreshToken, accessExpiry: Math.floor(runtime.now() / 1e3) + token.expiresIn, employeeId: token.employee.id, email: token.employee.email });
186
202
  await runtime.save(session);
187
- runtime.log("\u9489\u9489\u6388\u6743\u6210\u529F\uFF0C\u7EE7\u7EED\u6267\u884C\u5F53\u524D\u547D\u4EE4\u3002");
203
+ runtime.log("\u9489\u9489\u6388\u6743\u6210\u529F\u3002");
188
204
  return session;
189
205
  } catch (error) {
190
- if (!(error instanceof HttpError) || error.status !== 428) throw error;
206
+ if (!isAuthorizationPending(error)) throw error;
191
207
  if (runtime.now() >= nextProgressAt) {
192
208
  runtime.log("\u4ECD\u5728\u7B49\u5F85\u9489\u9489\u6388\u6743\u2026\u2026");
193
209
  nextProgressAt = runtime.now() + 15e3;
@@ -197,7 +213,7 @@ ${start.verificationUriComplete}
197
213
  throw new Error("device authorization expired");
198
214
  }
199
215
  async function runLogin(channel) {
200
- return withAuthWaitMarker(() => authorizeDevice(channel, {
216
+ return authorizeDevice(channel, {
201
217
  start: (session) => post(session, "/auth/device/start", { clientVersion: VERSION }),
202
218
  poll: (session, deviceCode) => post(session, "/auth/device/token", { deviceCode, clientVersion: VERSION }),
203
219
  openBrowser: async (url) => {
@@ -207,13 +223,10 @@ async function runLogin(channel) {
207
223
  sleep,
208
224
  now: Date.now,
209
225
  log: (message) => console.error(message)
210
- }));
226
+ });
211
227
  }
212
228
  function login(channel) {
213
- if (!loginInFlight) loginInFlight = runLogin(channel).finally(() => {
214
- loginInFlight = void 0;
215
- });
216
- return loginInFlight;
229
+ return runLogin(channel);
217
230
  }
218
231
  async function ensureAccess(session) {
219
232
  if (session.accessToken && Date.now() / 1e3 + 30 < session.accessExpiry) return session;
@@ -227,19 +240,17 @@ async function resolveAuthenticated(runtime) {
227
240
  return await runtime.refresh(await runtime.load());
228
241
  } catch (error) {
229
242
  if (error instanceof SessionNotFoundError) {
230
- console.error("CXClaw \u5C1A\u672A\u6388\u6743\uFF0C\u6B63\u5728\u81EA\u52A8\u53D1\u8D77\u9489\u9489\u6388\u6743\u3002");
231
- return runtime.authorize();
243
+ throw notAuthenticated();
232
244
  }
233
245
  if (error instanceof HttpError && error.status === 401) {
234
- console.error("CXClaw \u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u6B63\u5728\u91CD\u65B0\u53D1\u8D77\u9489\u9489\u6388\u6743\u3002");
235
246
  await runtime.remove().catch(() => void 0);
236
- return runtime.authorize();
247
+ throw notAuthenticated("CXClaw \u767B\u5F55\u5DF2\u5931\u6548");
237
248
  }
238
249
  throw error;
239
250
  }
240
251
  }
241
252
  function authenticated() {
242
- return resolveAuthenticated({ load: loadSession, refresh: ensureAccess, remove: deleteSession, authorize: () => login("stable") });
253
+ return resolveAuthenticated({ load: loadSession, refresh: ensureAccess, remove: deleteSession });
243
254
  }
244
255
  async function logout() {
245
256
  let session;
@@ -291,10 +302,10 @@ import { dirname as dirname2, resolve } from "path";
291
302
  import { fileURLToPath } from "url";
292
303
 
293
304
  // src/solvea/commands.ts
294
- import { readFile as readFile4 } from "fs/promises";
305
+ import { readFile as readFile3 } from "fs/promises";
295
306
 
296
307
  // src/solvea/client.ts
297
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
308
+ import { mkdir, readFile, writeFile } from "fs/promises";
298
309
  import { basename, dirname, extname } from "path";
299
310
  import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
300
311
  var KNOWLEDGE_TYPES = /* @__PURE__ */ new Set(["QA", "LEARN_SELF", "FILE", "WEBSITE", "PRODUCT"]);
@@ -742,7 +753,7 @@ var SolveaClient = class {
742
753
  await client.send(new PutObjectCommand({
743
754
  Bucket: String(credentials.bucketName),
744
755
  Key: key,
745
- Body: await readFile2(filePath),
756
+ Body: await readFile(filePath),
746
757
  ContentType: contentTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream"
747
758
  }));
748
759
  return key;
@@ -759,8 +770,8 @@ var SolveaClient = class {
759
770
  signal: AbortSignal.timeout(3e4)
760
771
  });
761
772
  if (!response.ok) throw new Error(`HTTP ${response.status} GET ${path}: ${await response.text()}`);
762
- await mkdir2(dirname(target), { recursive: true });
763
- await writeFile2(target, new Uint8Array(await response.arrayBuffer()));
773
+ await mkdir(dirname(target), { recursive: true });
774
+ await writeFile(target, new Uint8Array(await response.arrayBuffer()));
764
775
  return target;
765
776
  }
766
777
  async downloadLabelTemplate(templateType, target) {
@@ -1002,10 +1013,10 @@ var SolveaClient = class {
1002
1013
  };
1003
1014
 
1004
1015
  // src/solvea/input.ts
1005
- import { readFile as readFile3 } from "fs/promises";
1016
+ import { readFile as readFile2 } from "fs/promises";
1006
1017
  async function jsonData(args, required = true) {
1007
1018
  const file = option(args, "--data-file");
1008
- const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
1019
+ const raw = file ? await readFile2(file, "utf8") : option(args, "--data");
1009
1020
  if (!raw) {
1010
1021
  if (required) throw new Error("--data or --data-file is required");
1011
1022
  return {};
@@ -1016,7 +1027,7 @@ async function jsonData(args, required = true) {
1016
1027
  }
1017
1028
  async function jsonValue(args) {
1018
1029
  const file = option(args, "--data-file");
1019
- const raw = file ? await readFile3(file, "utf8") : option(args, "--data", true);
1030
+ const raw = file ? await readFile2(file, "utf8") : option(args, "--data", true);
1020
1031
  return JSON.parse(raw);
1021
1032
  }
1022
1033
  function requireFlag(args, name, command) {
@@ -1199,7 +1210,7 @@ function enabled(args, command) {
1199
1210
  }
1200
1211
  async function data2(args) {
1201
1212
  const file = option(args, "--data-file");
1202
- const raw = file ? await readFile4(file, "utf8") : option(args, "--data");
1213
+ const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
1203
1214
  if (!raw) throw new Error("--data or --data-file is required");
1204
1215
  const parsed = JSON.parse(raw);
1205
1216
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("request data must be a JSON object");
@@ -1544,13 +1555,13 @@ async function runResourceCommand(session, resource, action2, args) {
1544
1555
 
1545
1556
  // src/doctor.ts
1546
1557
  import { access } from "fs/promises";
1547
- import { join as join2 } from "path";
1558
+ import { join } from "path";
1548
1559
  async function diagnose() {
1549
1560
  const root2 = packageRoot();
1550
1561
  const requiredFiles = [
1551
1562
  "package.json"
1552
1563
  ];
1553
- await Promise.all(requiredFiles.map((path) => access(join2(root2, path))));
1564
+ await Promise.all(requiredFiles.map((path) => access(join(root2, path))));
1554
1565
  const expectedPluginVersion = process.env.CXCLAW_PLUGIN_VERSION || null;
1555
1566
  if (expectedPluginVersion && expectedPluginVersion !== VERSION) {
1556
1567
  throw new Error(
@@ -1602,9 +1613,9 @@ function publicTenant(t) {
1602
1613
 
1603
1614
  // src/update.ts
1604
1615
  import { spawn } from "child_process";
1605
- import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1616
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
1606
1617
  import { homedir, platform } from "os";
1607
- import { isAbsolute, join as join3 } from "path";
1618
+ import { isAbsolute, join as join2 } from "path";
1608
1619
  var exec = (command, args, options3 = {}) => new Promise((resolve5, reject) => {
1609
1620
  const chunks = [];
1610
1621
  const child = spawn(command, args, {
@@ -1677,11 +1688,11 @@ async function update() {
1677
1688
  async function installScheduler() {
1678
1689
  const invocation = schedulerInvocation();
1679
1690
  if (platform() === "darwin") {
1680
- const dir = join3(homedir(), "Library/LaunchAgents");
1681
- const path = join3(dir, "com.solvea.cxclaw.update.plist");
1691
+ const dir = join2(homedir(), "Library/LaunchAgents");
1692
+ const path = join2(dir, "com.solvea.cxclaw.update.plist");
1682
1693
  const programArguments = [invocation.command, ...invocation.args].map((value) => `<string>${xml(value)}</string>`).join("");
1683
- await mkdir3(dir, { recursive: true });
1684
- await writeFile3(
1694
+ await mkdir2(dir, { recursive: true });
1695
+ await writeFile2(
1685
1696
  path,
1686
1697
  `<?xml version="1.0" encoding="UTF-8"?>
1687
1698
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -1693,18 +1704,18 @@ async function installScheduler() {
1693
1704
  return;
1694
1705
  }
1695
1706
  if (platform() === "linux") {
1696
- const dir = join3(homedir(), ".config/systemd/user");
1707
+ const dir = join2(homedir(), ".config/systemd/user");
1697
1708
  const command = [invocation.command, ...invocation.args].map(systemdArg).join(" ");
1698
- await mkdir3(dir, { recursive: true });
1699
- await writeFile3(
1700
- join3(dir, "cxclaw-update.service"),
1709
+ await mkdir2(dir, { recursive: true });
1710
+ await writeFile2(
1711
+ join2(dir, "cxclaw-update.service"),
1701
1712
  `[Service]
1702
1713
  Type=oneshot
1703
1714
  ExecStart=${command}
1704
1715
  `
1705
1716
  );
1706
- await writeFile3(
1707
- join3(dir, "cxclaw-update.timer"),
1717
+ await writeFile2(
1718
+ join2(dir, "cxclaw-update.timer"),
1708
1719
  "[Timer]\nOnBootSec=5m\nOnUnitActiveSec=6h\nPersistent=true\n[Install]\nWantedBy=timers.target\n"
1709
1720
  );
1710
1721
  await exec("systemctl", ["--user", "daemon-reload"]);
@@ -1743,12 +1754,12 @@ async function installMarketplace(channel) {
1743
1754
  // src/workflows/runtime.ts
1744
1755
  import { execFile } from "child_process";
1745
1756
  import { promises as fs } from "fs";
1746
- import { join as join4, resolve as resolve2 } from "path";
1757
+ import { join as join3, resolve as resolve2 } from "path";
1747
1758
  import { promisify } from "util";
1748
1759
  var exec2 = promisify(execFile);
1749
- var workspace = () => resolve2(process.env.WORKSPACE_DIR ?? join4(process.cwd(), "workspace"));
1750
- var root = () => join4(workspace(), "runtime-inspector");
1751
- var dirs = () => ({ output: join4(root(), "outputs"), state: join4(root(), "state"), tmp: join4(root(), "tmp") });
1760
+ var workspace = () => resolve2(process.env.WORKSPACE_DIR ?? join3(process.cwd(), "workspace"));
1761
+ var root = () => join3(workspace(), "runtime-inspector");
1762
+ var dirs = () => ({ output: join3(root(), "outputs"), state: join3(root(), "state"), tmp: join3(root(), "tmp") });
1752
1763
  var timestamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1753
1764
  var readJson = async (path, fallback) => {
1754
1765
  try {
@@ -1784,26 +1795,26 @@ async function prepare(args) {
1784
1795
  await fs.mkdir(tmp, { recursive: true });
1785
1796
  const batches = [];
1786
1797
  for (let i = 0; i < records.length; i += batchSize) batches.push(records.slice(i, i + batchSize));
1787
- await Promise.all(batches.map((batch, i) => writeJson(join4(tmp, `batch_${String(i).padStart(3, "0")}.json`), batch)));
1788
- await writeJson(join4(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() });
1798
+ await Promise.all(batches.map((batch, i) => writeJson(join3(tmp, `batch_${String(i).padStart(3, "0")}.json`), batch)));
1799
+ 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() });
1789
1800
  return { status: "batched", totalRecords: records.length, totalBatches: batches.length, tmp };
1790
1801
  }
1791
1802
  async function processBatches() {
1792
1803
  const { tmp, output, state: state2 } = dirs();
1793
- const current = await readJson(join4(state2, "inspect.json"), {});
1804
+ const current = await readJson(join3(state2, "inspect.json"), {});
1794
1805
  if (current.status !== "batched") throw new Error(`runtime state must be batched, got ${String(current.status ?? "missing")}`);
1795
1806
  const names = (await fs.readdir(tmp)).filter((name) => /^batch_\d+\.json$/.test(name)).sort();
1796
1807
  if (!names.length) throw new Error(`no batch files found in ${tmp}`);
1797
1808
  const records = [];
1798
- for (const name of names) for (const row of await readJson(join4(tmp, name), [])) records.push({ ...row, _processed: true, _summary: `processed: ${JSON.stringify(row).slice(0, 60)}`, _at: (/* @__PURE__ */ new Date()).toISOString() });
1799
- const path = join4(output, `results_${timestamp()}.json`);
1809
+ 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() });
1810
+ const path = join3(output, `results_${timestamp()}.json`);
1800
1811
  await writeJson(path, { total: records.length, processed_at: (/* @__PURE__ */ new Date()).toISOString(), source: current.source, records });
1801
- await writeJson(join4(state2, "inspect.json"), { status: "done", total_processed: records.length, results_path: path, done_at: (/* @__PURE__ */ new Date()).toISOString() });
1812
+ await writeJson(join3(state2, "inspect.json"), { status: "done", total_processed: records.length, results_path: path, done_at: (/* @__PURE__ */ new Date()).toISOString() });
1802
1813
  return { status: "done", total: records.length, resultsPath: path };
1803
1814
  }
1804
1815
  async function state() {
1805
1816
  const { state: stateDir2, output, tmp } = dirs();
1806
- return { state: await readJson(join4(stateDir2, "inspect.json"), null), outputFiles: await fs.readdir(output).catch(() => []), tmpFiles: await fs.readdir(tmp).catch(() => []) };
1817
+ return { state: await readJson(join3(stateDir2, "inspect.json"), null), outputFiles: await fs.readdir(output).catch(() => []), tmpFiles: await fs.readdir(tmp).catch(() => []) };
1807
1818
  }
1808
1819
  async function verify() {
1809
1820
  const snapshot = await state();
@@ -1830,7 +1841,7 @@ async function sandbox(args) {
1830
1841
  }
1831
1842
  async function model(args) {
1832
1843
  if (option(args, "--scenario", true) !== "truncation") throw new Error("only --scenario truncation is supported");
1833
- const target = join4(dirs().tmp, "truncation_test.md");
1844
+ const target = join3(dirs().tmp, "truncation_test.md");
1834
1845
  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." };
1835
1846
  }
1836
1847
  async function runRuntime(action2, args) {
@@ -1843,9 +1854,9 @@ async function runRuntime(action2, args) {
1843
1854
  if (action2 === "write-test") {
1844
1855
  const { output, state: stateDir2 } = dirs();
1845
1856
  const runId = timestamp();
1846
- await writeJson(join4(output, `${runId}_test.json`), { run_id: runId, written_at: (/* @__PURE__ */ new Date()).toISOString() });
1847
- const current = await readJson(join4(stateDir2, "inspect.json"), {});
1848
- await writeJson(join4(stateDir2, "inspect.json"), { ...current, last_run_id: runId, write_count: Number(current.write_count ?? 0) + 1 });
1857
+ await writeJson(join3(output, `${runId}_test.json`), { run_id: runId, written_at: (/* @__PURE__ */ new Date()).toISOString() });
1858
+ const current = await readJson(join3(stateDir2, "inspect.json"), {});
1859
+ await writeJson(join3(stateDir2, "inspect.json"), { ...current, last_run_id: runId, write_count: Number(current.write_count ?? 0) + 1 });
1849
1860
  return { ok: true, runId };
1850
1861
  }
1851
1862
  throw new Error("runtime action must be prepare, process, state, verify, sandbox, model, or write-test");
@@ -1854,10 +1865,10 @@ async function runRuntime(action2, args) {
1854
1865
  // src/workflows/solvea-kit.ts
1855
1866
  import ExcelJS from "exceljs";
1856
1867
  import { promises as fs2 } from "fs";
1857
- import { dirname as dirname3, join as join5, resolve as resolve3 } from "path";
1858
- var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ?? join5(process.cwd(), "workspace"));
1859
- var outputDir = (owner) => join5(workspace2(), "outputs", owner);
1860
- var stateDir = (owner) => join5(workspace2(), "state", owner);
1868
+ import { dirname as dirname3, join as join4, resolve as resolve3 } from "path";
1869
+ var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ?? join4(process.cwd(), "workspace"));
1870
+ var outputDir = (owner) => join4(workspace2(), "outputs", owner);
1871
+ var stateDir = (owner) => join4(workspace2(), "state", owner);
1861
1872
  var now = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1862
1873
  var readJson2 = async (path) => JSON.parse(await fs2.readFile(path, "utf8"));
1863
1874
  var writeJson2 = async (path, value) => {
@@ -1887,7 +1898,7 @@ function labelsFrom(value) {
1887
1898
  async function generateLabelImport(args) {
1888
1899
  const input = option(args, "--input") ?? option(args, "--data-file", true);
1889
1900
  const init = args.includes("--init");
1890
- const output = option(args, "--output") ?? join5(stateDir("solvea-kit"), init ? "labels_init.xlsx" : "labels_update.xlsx");
1901
+ const output = option(args, "--output") ?? join4(stateDir("solvea-kit"), init ? "labels_init.xlsx" : "labels_update.xlsx");
1891
1902
  const labels = labelsFrom(await readJson2(input));
1892
1903
  const workbook = new ExcelJS.Workbook();
1893
1904
  const sheet = workbook.addWorksheet("labels");
@@ -1927,9 +1938,9 @@ async function classifyIntents(args) {
1927
1938
  if (!noExcel && !option(args, "--xlsx")) throw new Error("provide --xlsx or --no-excel");
1928
1939
  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 }));
1929
1940
  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: [] };
1930
- const resultPath = join5(outputDir(owner), `results_${runId}.json`);
1941
+ const resultPath = join4(outputDir(owner), `results_${runId}.json`);
1931
1942
  await writeJson2(resultPath, result);
1932
- await writeJson2(join5(stateDir(owner), "progress.json"), { status: "ready", run_id: runId, results_path: resultPath, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1943
+ await writeJson2(join4(stateDir(owner), "progress.json"), { status: "ready", run_id: runId, results_path: resultPath, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1933
1944
  return { ...result.meta, resultsPath: resultPath };
1934
1945
  }
1935
1946
  async function runSolveaKitWorkflow(action2, args) {
@@ -1939,7 +1950,7 @@ async function runSolveaKitWorkflow(action2, args) {
1939
1950
  }
1940
1951
 
1941
1952
  // src/workflows/support.ts
1942
- import { readFile as readFile5 } from "fs/promises";
1953
+ import { readFile as readFile4 } from "fs/promises";
1943
1954
  import { basename as basename3 } from "path";
1944
1955
  var safe = (value) => encodeURIComponent(value);
1945
1956
  var docsMcpUrl = process.env.CXCLAW_DOCS_MCP_URL ?? "https://solvea-39f11a36.mintlify.app/mcp";
@@ -2014,7 +2025,7 @@ async function runSupport(session, action2, args) {
2014
2025
  const attachments = [];
2015
2026
  for (const file of options2(args, "--attachment")) {
2016
2027
  const form = new FormData();
2017
- form.append("file", new Blob([await readFile5(file)]), basename3(file));
2028
+ form.append("file", new Blob([await readFile4(file)]), basename3(file));
2018
2029
  const tenant = session.tenant;
2019
2030
  const base = tenant?.businessUrl?.replace(/\/$/, "");
2020
2031
  if (!tenant || !base || !tenant.businessToken) throw new Error("no tenant selected");
@@ -2045,24 +2056,24 @@ async function runSupport(session, action2, args) {
2045
2056
  }
2046
2057
 
2047
2058
  // src/workflows/common.ts
2048
- import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
2049
- import { dirname as dirname4, join as join6, resolve as resolve4 } from "path";
2059
+ import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
2060
+ import { dirname as dirname4, join as join5, resolve as resolve4 } from "path";
2050
2061
  import { homedir as homedir2 } from "os";
2051
- var workspaceRoot = () => resolve4(process.env.CXCLAW_WORKSPACE ?? join6(homedir2(), ".cxclaw", "workspace"));
2052
- var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ?? join6(workspaceRoot(), "state"), domain);
2053
- var outputRoot = (domain) => resolve4(process.env.CXCLAW_OUTPUT_DIR ?? join6(workspaceRoot(), "outputs"), domain);
2062
+ var workspaceRoot = () => resolve4(process.env.CXCLAW_WORKSPACE ?? join5(homedir2(), ".cxclaw", "workspace"));
2063
+ var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ?? join5(workspaceRoot(), "state"), domain);
2064
+ var outputRoot = (domain) => resolve4(process.env.CXCLAW_OUTPUT_DIR ?? join5(workspaceRoot(), "outputs"), domain);
2054
2065
  async function ensureParent(file) {
2055
- await mkdir4(dirname4(file), { recursive: true });
2066
+ await mkdir3(dirname4(file), { recursive: true });
2056
2067
  }
2057
2068
  async function ensureDir(directory) {
2058
- await mkdir4(directory, { recursive: true });
2069
+ await mkdir3(directory, { recursive: true });
2059
2070
  }
2060
2071
  async function readJson3(file) {
2061
- return JSON.parse(await readFile6(file, "utf8"));
2072
+ return JSON.parse(await readFile5(file, "utf8"));
2062
2073
  }
2063
2074
  async function writeJson3(file, value) {
2064
2075
  await ensureParent(file);
2065
- await writeFile4(file, `${JSON.stringify(value, null, 2)}
2076
+ await writeFile3(file, `${JSON.stringify(value, null, 2)}
2066
2077
  `, "utf8");
2067
2078
  }
2068
2079
  function intOption(args, name, fallback) {
@@ -2080,7 +2091,7 @@ function htmlEscape(value) {
2080
2091
  }
2081
2092
  async function writeHtml(file, title, body) {
2082
2093
  await ensureParent(file);
2083
- await writeFile4(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");
2094
+ await writeFile3(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");
2084
2095
  }
2085
2096
  function asRows(value) {
2086
2097
  if (Array.isArray(value)) return value.filter((item) => item && typeof item === "object");
@@ -2287,13 +2298,13 @@ async function runLocalAgentWorkflow(action2, args) {
2287
2298
  }
2288
2299
  async function writeFileText(file, content) {
2289
2300
  await ensureParent(file);
2290
- const { writeFile: writeFile5 } = await import("fs/promises");
2291
- await writeFile5(file, `${content}
2301
+ const { writeFile: writeFile4 } = await import("fs/promises");
2302
+ await writeFile4(file, `${content}
2292
2303
  `, "utf8");
2293
2304
  }
2294
2305
 
2295
2306
  // src/workflows/tester.ts
2296
- import { join as join7 } from "path";
2307
+ import { join as join6 } from "path";
2297
2308
  import ExcelJS2 from "exceljs";
2298
2309
  async function casesFrom(file) {
2299
2310
  if (file.endsWith(".json")) return asRows(await readJson3(file));
@@ -2315,7 +2326,7 @@ async function casesFrom(file) {
2315
2326
  }
2316
2327
  async function createSheet(args) {
2317
2328
  const cases = option(args, "--cases-file") ? await casesFrom(option(args, "--cases-file")) : [];
2318
- const output = option(args, "--output") ?? join7(outputRoot("agent-tester"), `cases_${Date.now()}.xlsx`);
2329
+ const output = option(args, "--output") ?? join6(outputRoot("agent-tester"), `cases_${Date.now()}.xlsx`);
2319
2330
  await ensureParent(output);
2320
2331
  const workbook = new ExcelJS2.Workbook();
2321
2332
  const sheet = workbook.addWorksheet("cases");
@@ -2341,7 +2352,7 @@ async function runAgentTester(session, action2, args) {
2341
2352
  }
2342
2353
 
2343
2354
  // src/workflows/delivery.ts
2344
- import { join as join8 } from "path";
2355
+ import { join as join7 } from "path";
2345
2356
  import ExcelJS3 from "exceljs";
2346
2357
  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"];
2347
2358
  async function loadRows(file) {
@@ -2375,7 +2386,7 @@ async function writeRows(file, rows) {
2375
2386
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2376
2387
  sheet.addRow(keys);
2377
2388
  rows.forEach((row) => sheet.addRow(keys.map((key) => row[key] ?? "")));
2378
- await ensureDir(join8(file, ".."));
2389
+ await ensureDir(join7(file, ".."));
2379
2390
  await workbook.xlsx.writeFile(file);
2380
2391
  }
2381
2392
  function classify(text) {
@@ -2396,13 +2407,13 @@ async function classifyCases(args, domain) {
2396
2407
  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" }));
2397
2408
  const runId = option(args, "--run-id") ?? Date.now().toString();
2398
2409
  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) };
2399
- const out = option(args, "--results") ?? join8(outputRoot(domain), `results_${runId}.json`);
2410
+ const out = option(args, "--results") ?? join7(outputRoot(domain), `results_${runId}.json`);
2400
2411
  await writeJson3(out, result);
2401
- await writeJson3(join8(stateRoot(domain), "progress.json"), { status: "classified", run_id: runId, results_path: out, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
2412
+ await writeJson3(join7(stateRoot(domain), "progress.json"), { status: "classified", run_id: runId, results_path: out, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
2402
2413
  return { ...result.meta, resultsPath: out };
2403
2414
  }
2404
2415
  async function plan(domain, args) {
2405
- const file = join8(stateRoot(domain), "progress.json");
2416
+ const file = join7(stateRoot(domain), "progress.json");
2406
2417
  let current = {};
2407
2418
  try {
2408
2419
  current = await readJson3(file);
@@ -2426,7 +2437,7 @@ async function plan(domain, args) {
2426
2437
  async function runBatch(client, args, domain) {
2427
2438
  const input = option(args, "--input") ?? option(args, "--test-file", true);
2428
2439
  const rows = await loadRows(input);
2429
- const output = option(args, "--output") ?? join8(outputRoot(domain), `test_results_${Date.now()}.json`);
2440
+ const output = option(args, "--output") ?? join7(outputRoot(domain), `test_results_${Date.now()}.json`);
2430
2441
  const workers = Math.max(1, Math.min(intOption(args, "--workers", 4), 16));
2431
2442
  const results = [];
2432
2443
  let cursor = 0;
@@ -2450,7 +2461,7 @@ async function runBatch(client, args, domain) {
2450
2461
  return { output, total: results.length, succeeded: results.filter((row) => row.ok).length, failed: results.filter((row) => !row.ok).length };
2451
2462
  }
2452
2463
  async function createAgents(client, args, domain) {
2453
- const state2 = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2464
+ const state2 = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2454
2465
  const resultsPath = option(args, "--results") ?? (typeof state2.results_path === "string" ? state2.results_path : void 0);
2455
2466
  if (!resultsPath) throw new Error("classification results are required");
2456
2467
  const result = await readJson3(resultsPath);
@@ -2461,12 +2472,12 @@ async function createAgents(client, args, domain) {
2461
2472
  return { created, count: created.length };
2462
2473
  }
2463
2474
  async function renderReport(args, domain) {
2464
- const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2475
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2465
2476
  const resultsFile = option(args, "--results") ?? option(args, "--input") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2466
2477
  if (!resultsFile) throw new Error("--results/--input is required, or run classify first");
2467
2478
  const value = await readJson3(resultsFile);
2468
2479
  const rows = asRows(value.results ?? value.items ?? value);
2469
- const output = option(args, "--html") ?? option(args, "--output") ?? join8(outputRoot(domain), `${domain}_report.html`);
2480
+ const output = option(args, "--html") ?? option(args, "--output") ?? join7(outputRoot(domain), `${domain}_report.html`);
2470
2481
  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("")}`;
2471
2482
  await writeHtml(output, option(args, "--title") ?? `${domain} report`, body);
2472
2483
  const md = option(args, "--md");
@@ -2477,12 +2488,12 @@ Total: ${rows.length}
2477
2488
  return { output, count: rows.length };
2478
2489
  }
2479
2490
  async function genExcel(args, domain) {
2480
- const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2491
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2481
2492
  const input = option(args, "--results") ?? option(args, "--items") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2482
2493
  if (!input) throw new Error("--results or --items is required, or run classify first");
2483
2494
  const value = await readJson3(input);
2484
2495
  const rows = asRows(value);
2485
- const output = option(args, "--output") ?? join8(outputRoot(domain), `${domain}_results.xlsx`);
2496
+ const output = option(args, "--output") ?? join7(outputRoot(domain), `${domain}_results.xlsx`);
2486
2497
  await writeRows(output, rows);
2487
2498
  return { output, count: rows.length };
2488
2499
  }
@@ -2522,7 +2533,7 @@ async function runDomain(session, domain, action2, args) {
2522
2533
  }
2523
2534
 
2524
2535
  // src/workflows/kb-builder.ts
2525
- import { join as join9 } from "path";
2536
+ import { join as join8 } from "path";
2526
2537
  import ExcelJS4 from "exceljs";
2527
2538
  var clean = (value) => String(value ?? "").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
2528
2539
  var absolute = (href, base) => {
@@ -2556,7 +2567,7 @@ async function crawl(args) {
2556
2567
  }
2557
2568
  }
2558
2569
  const result = { url, mode: option(args, "--mode") ?? "auto", pages, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), total: pages.length };
2559
- const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), "crawl_result.json");
2570
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "crawl_result.json");
2560
2571
  await writeJson3(output, result);
2561
2572
  return { ...result, output };
2562
2573
  }
@@ -2571,13 +2582,13 @@ async function directoryPlan(args) {
2571
2582
  }
2572
2583
  const tree = [...groups.entries()].map(([name, pages]) => ({ name, children: pages.slice(0, 100).map((page2) => ({ name: String(page2.title ?? page2.url), sourceUrl: page2.url })) }));
2573
2584
  const result = { source: option(args, "--crawl-result"), generatedAt: (/* @__PURE__ */ new Date()).toISOString(), tree, confirmed: false };
2574
- const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), "directory_plan.json");
2585
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "directory_plan.json");
2575
2586
  await writeJson3(output, result);
2576
- if (flag(args, "--write-confirmed-tree")) await writeJson3(join9(stateRoot("kb-builder"), "confirmed_tree.json"), { ...result, confirmed: true });
2587
+ if (flag(args, "--write-confirmed-tree")) await writeJson3(join8(stateRoot("kb-builder"), "confirmed_tree.json"), { ...result, confirmed: true });
2577
2588
  return { output, directories: tree.length, pages: rows.length, tree };
2578
2589
  }
2579
2590
  async function createDirectories(client, args) {
2580
- const file = option(args, "--tree-file") ?? join9(stateRoot("kb-builder"), "confirmed_tree.json");
2591
+ const file = option(args, "--tree-file") ?? join8(stateRoot("kb-builder"), "confirmed_tree.json");
2581
2592
  const value = await readJson3(file);
2582
2593
  const tree = Array.isArray(value.tree) ? value.tree : Array.isArray(value) ? value : [];
2583
2594
  if (!tree.length) throw new Error("confirmed directory tree is empty");
@@ -2600,12 +2611,12 @@ async function createDirectories(client, args) {
2600
2611
  async function extractWebQa(args) {
2601
2612
  const input = await readJson3(option(args, "--crawl-result", true));
2602
2613
  const pages = asRows(input.pages ?? input).slice(0, intOption(args, "--max-pages", 80));
2603
- const outputDir2 = option(args, "--output-dir") ?? join9(outputRoot("kb-builder"), "qa_parts");
2614
+ const outputDir2 = option(args, "--output-dir") ?? join8(outputRoot("kb-builder"), "qa_parts");
2604
2615
  await ensureDir(outputDir2);
2605
2616
  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 }));
2606
2617
  const files = [];
2607
2618
  for (const [index, part] of parts.entries()) {
2608
- const file = join9(outputDir2, `part_${String(index + 1).padStart(4, "0")}.json`);
2619
+ const file = join8(outputDir2, `part_${String(index + 1).padStart(4, "0")}.json`);
2609
2620
  await writeJson3(file, { items: [part] });
2610
2621
  files.push(file);
2611
2622
  }
@@ -2671,9 +2682,9 @@ async function importQa(client, args) {
2671
2682
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2672
2683
  }
2673
2684
  if (fromDir) {
2674
- const { readdir: readdir2 } = await import("fs/promises");
2675
- for (const file of (await readdir2(fromDir)).filter((name) => name.endsWith(".json")).sort()) {
2676
- const value = await readJson3(join9(fromDir, file));
2685
+ const { readdir } = await import("fs/promises");
2686
+ for (const file of (await readdir(fromDir)).filter((name) => name.endsWith(".json")).sort()) {
2687
+ const value = await readJson3(join8(fromDir, file));
2677
2688
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2678
2689
  }
2679
2690
  }
@@ -2681,7 +2692,7 @@ async function importQa(client, args) {
2681
2692
  if (!Number.isSafeInteger(maxDepth) || maxDepth <= 0) throw new Error("--max-depth must be a positive integer");
2682
2693
  const normalized = validateQaItems(items, maxDepth);
2683
2694
  const plan2 = { items, count: items.length, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
2684
- const planFile = join9(outputRoot("kb-builder"), `qa_import_plan_${Date.now()}.json`);
2695
+ const planFile = join8(outputRoot("kb-builder"), `qa_import_plan_${Date.now()}.json`);
2685
2696
  await writeJson3(planFile, plan2);
2686
2697
  if (flag(args, "--dry-run")) return { dryRun: true, planFile, count: items.length };
2687
2698
  const directories = flattenDirectories(asRows(await client.listDirectories()));
@@ -2756,7 +2767,7 @@ async function importTemplates(client, args) {
2756
2767
  });
2757
2768
  }
2758
2769
  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);
2759
- const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `template_import_plan_${Date.now()}.json`);
2770
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `template_import_plan_${Date.now()}.json`);
2760
2771
  await writeJson3(output, { items, count: items.length });
2761
2772
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
2762
2773
  const results = [];
@@ -2771,13 +2782,13 @@ async function exportKnowledge(client, args) {
2771
2782
  const value = await client.listKnowledge({ directoryId: id, keyword: option(args, "--keyword") ?? "", type: option(args, "--type") ?? "ALL", pageSize: intOption(args, "--page-size", 1e3) });
2772
2783
  rows.push(...asRows(value).map((row) => ({ ...row, directoryId: id, directoryName: directories.find((dir) => Number(dir.id ?? dir.directoryId) === id)?.name ?? "" })));
2773
2784
  }
2774
- const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `knowledge_${Date.now()}.xlsx`);
2785
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `knowledge_${Date.now()}.xlsx`);
2775
2786
  const workbook = new ExcelJS4.Workbook();
2776
2787
  const sheet = workbook.addWorksheet("knowledge");
2777
2788
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2778
2789
  sheet.addRow(keys);
2779
2790
  for (const row of rows) sheet.addRow(keys.map((key) => row[key] ?? ""));
2780
- await ensureDir(join9(output, ".."));
2791
+ await ensureDir(join8(output, ".."));
2781
2792
  await workbook.xlsx.writeFile(output);
2782
2793
  return { output, count: rows.length };
2783
2794
  }
@@ -2818,7 +2829,7 @@ async function extractTicketQa(args) {
2818
2829
  const answer = String(record[replyCol] ?? "").trim();
2819
2830
  if (question && question !== `${brand}:`) items.push({ question, answer, sourceRow: number });
2820
2831
  });
2821
- const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `ticket_qa_${Date.now()}.json`);
2832
+ const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `ticket_qa_${Date.now()}.json`);
2822
2833
  const result = { brand, count: items.length, items };
2823
2834
  await writeJson3(output, result);
2824
2835
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
@@ -2826,12 +2837,12 @@ async function extractTicketQa(args) {
2826
2837
  }
2827
2838
 
2828
2839
  // src/workflows/desk.ts
2829
- import { join as join10 } from "path";
2840
+ import { join as join9 } from "path";
2830
2841
  import ExcelJS5 from "exceljs";
2831
2842
  var taskId = (args) => option(args, "--task-id") ?? (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
2832
- var taskDir = (args) => join10(stateRoot("solvea-desk"), taskId(args));
2843
+ var taskDir = (args) => join9(stateRoot("solvea-desk"), taskId(args));
2833
2844
  async function saveDatasource(dir, name, rows) {
2834
- const file = join10(dir, name);
2845
+ const file = join9(dir, name);
2835
2846
  await ensureParent(file);
2836
2847
  const workbook = new ExcelJS5.Workbook();
2837
2848
  const sheet = workbook.addWorksheet("data");
@@ -2854,7 +2865,7 @@ async function fetchTickets(client, args) {
2854
2865
  if (pageRows.length < pageSize2) break;
2855
2866
  }
2856
2867
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2857
- await writeJson3(join10(dir, "metadata.json"), { taskId: taskId(args), rows: rows.length, output });
2868
+ await writeJson3(join9(dir, "metadata.json"), { taskId: taskId(args), rows: rows.length, output });
2858
2869
  return { taskId: taskId(args), output, count: rows.length };
2859
2870
  }
2860
2871
  async function fetchSources(client, args) {
@@ -2865,7 +2876,7 @@ async function fetchSources(client, args) {
2865
2876
  const rows = asRows(value).slice(0, intOption(args, "--max-rows", 1e4));
2866
2877
  sources.tickets = rows;
2867
2878
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2868
- await writeJson3(join10(dir, "sources.json"), sources);
2879
+ await writeJson3(join9(dir, "sources.json"), sources);
2869
2880
  return { taskId: taskId(args), output, count: rows.length };
2870
2881
  }
2871
2882
  async function tags(client, action2, args) {
@@ -2892,10 +2903,10 @@ async function tags(client, action2, args) {
2892
2903
  throw new Error(`unknown tag action: ${action2}`);
2893
2904
  }
2894
2905
  async function renderReport2(args) {
2895
- const dir = taskDir(args), dataFile = option(args, "--report-data") ?? join10(dir, "report_data.json"), notesFile = option(args, "--notes") ?? join10(dir, "calculation_notes.json");
2906
+ const dir = taskDir(args), dataFile = option(args, "--report-data") ?? join9(dir, "report_data.json"), notesFile = option(args, "--notes") ?? join9(dir, "calculation_notes.json");
2896
2907
  const data3 = await readJson3(dataFile);
2897
2908
  if (flag(args, "--validate-only")) return { valid: true, dataFile };
2898
- const output = option(args, "--output") ?? join10(outputRoot("solvea-desk"), taskId(args), `${option(args, "--report-slug") ?? "report"}.html`);
2909
+ const output = option(args, "--output") ?? join9(outputRoot("solvea-desk"), taskId(args), `${option(args, "--report-slug") ?? "report"}.html`);
2899
2910
  const body = `<pre>${htmlEscape(JSON.stringify({ data: data3, notes: await readJson3(notesFile).catch(() => ({})) }, null, 2))}</pre>`;
2900
2911
  await writeHtml(output, option(args, "--report-slug") ?? "Solvea Desk report", body);
2901
2912
  return { output, valid: true };
@@ -2926,7 +2937,6 @@ async function runAuth(action2, args) {
2926
2937
  const session = await login(option(args, "--channel") ?? "stable");
2927
2938
  return print(publicAuthStatus(session));
2928
2939
  }
2929
- if (action2 === "ensure") return print(publicAuthStatus(await authenticated()));
2930
2940
  if (action2 === "logout") {
2931
2941
  await logout();
2932
2942
  return print({ ok: true, loggedOut: true });
@@ -2942,7 +2952,7 @@ async function runAuth(action2, args) {
2942
2952
  if (action2 === "refresh") {
2943
2953
  return print(publicAuthStatus(await authenticated()));
2944
2954
  }
2945
- throw new Error("auth action must be login, ensure, logout, status, or refresh");
2955
+ throw new Error("auth action must be login, logout, status, or refresh");
2946
2956
  }
2947
2957
  async function runTenant(action2, args) {
2948
2958
  const session = await authenticated();
@@ -3015,11 +3025,12 @@ async function main(args = process.argv.slice(2)) {
3015
3025
  if (flag(args, "--scheduled")) await new Promise((resolve5) => setTimeout(resolve5, Math.random() * 18e5));
3016
3026
  return print(await update());
3017
3027
  }
3018
- if (command === "commands" || command === "capabilities") console.log(await readFile7(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
3028
+ if (command === "commands" || command === "capabilities") console.log(await readFile6(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
3019
3029
  else throw new Error(`unknown command: ${command}`);
3020
3030
  }
3021
3031
  main().catch((error) => {
3022
- console.error(`cxclawctl: ${error instanceof Error ? error.message : String(error)}`);
3023
- process.exitCode = 1;
3032
+ const output = errorOutput(error);
3033
+ console.error(JSON.stringify(output));
3034
+ process.exitCode = output.error.code;
3024
3035
  });
3025
3036
  //# sourceMappingURL=cli.js.map