@shulex/cxclawctl 0.1.12 → 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.12",
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: {
@@ -141,35 +140,41 @@ async function deleteSession() {
141
140
  await entry().deleteCredential();
142
141
  }
143
142
 
144
- // runtime/auth-wait-state.mjs
145
- import { createHash } from "crypto";
146
- import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises";
147
- import { tmpdir } from "os";
148
- import { join } from "path";
149
- var markerRoot = join(tmpdir(), "cxclaw-auth-wait");
150
- var markerTtlMs = 15 * 60 * 1e3;
151
- var markerName = (sessionId, pid) => `${createHash("sha256").update(sessionId).digest("hex").slice(0, 24)}-${pid}.json`;
152
- async function withAuthWaitMarker(operation, env = process.env) {
153
- const sessionId = env.CODEX_SESSION_ID ?? env.CODEX_THREAD_ID;
154
- if (!sessionId) return operation();
155
- await mkdir(markerRoot, { recursive: true, mode: 448 });
156
- const path = join(markerRoot, markerName(sessionId, process.pid));
157
- await writeFile(path, JSON.stringify({
158
- sessionId,
159
- threadId: env.CODEX_THREAD_ID ?? null,
160
- pid: process.pid,
161
- expiresAt: Date.now() + markerTtlMs
162
- }), { mode: 384 });
163
- try {
164
- return await operation();
165
- } finally {
166
- await rm(path, { force: true }).catch(() => void 0);
167
- }
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
+ };
168
174
  }
169
175
 
170
176
  // src/auth.ts
171
177
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
172
- var loginInFlight;
173
178
  function publicAuthStatus(session) {
174
179
  return { ok: true, loggedIn: true, email: session.email, channel: session.channel, accessExpiresAt: session.accessExpiry };
175
180
  }
@@ -195,7 +200,7 @@ ${start.verificationUriComplete}
195
200
  const token = await runtime.poll(session, start.deviceCode);
196
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 });
197
202
  await runtime.save(session);
198
- 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");
199
204
  return session;
200
205
  } catch (error) {
201
206
  if (!isAuthorizationPending(error)) throw error;
@@ -208,7 +213,7 @@ ${start.verificationUriComplete}
208
213
  throw new Error("device authorization expired");
209
214
  }
210
215
  async function runLogin(channel) {
211
- return withAuthWaitMarker(() => authorizeDevice(channel, {
216
+ return authorizeDevice(channel, {
212
217
  start: (session) => post(session, "/auth/device/start", { clientVersion: VERSION }),
213
218
  poll: (session, deviceCode) => post(session, "/auth/device/token", { deviceCode, clientVersion: VERSION }),
214
219
  openBrowser: async (url) => {
@@ -218,13 +223,10 @@ async function runLogin(channel) {
218
223
  sleep,
219
224
  now: Date.now,
220
225
  log: (message) => console.error(message)
221
- }));
226
+ });
222
227
  }
223
228
  function login(channel) {
224
- if (!loginInFlight) loginInFlight = runLogin(channel).finally(() => {
225
- loginInFlight = void 0;
226
- });
227
- return loginInFlight;
229
+ return runLogin(channel);
228
230
  }
229
231
  async function ensureAccess(session) {
230
232
  if (session.accessToken && Date.now() / 1e3 + 30 < session.accessExpiry) return session;
@@ -238,19 +240,17 @@ async function resolveAuthenticated(runtime) {
238
240
  return await runtime.refresh(await runtime.load());
239
241
  } catch (error) {
240
242
  if (error instanceof SessionNotFoundError) {
241
- console.error("CXClaw \u5C1A\u672A\u6388\u6743\uFF0C\u6B63\u5728\u81EA\u52A8\u53D1\u8D77\u9489\u9489\u6388\u6743\u3002");
242
- return runtime.authorize();
243
+ throw notAuthenticated();
243
244
  }
244
245
  if (error instanceof HttpError && error.status === 401) {
245
- console.error("CXClaw \u767B\u5F55\u5DF2\u5931\u6548\uFF0C\u6B63\u5728\u91CD\u65B0\u53D1\u8D77\u9489\u9489\u6388\u6743\u3002");
246
246
  await runtime.remove().catch(() => void 0);
247
- return runtime.authorize();
247
+ throw notAuthenticated("CXClaw \u767B\u5F55\u5DF2\u5931\u6548");
248
248
  }
249
249
  throw error;
250
250
  }
251
251
  }
252
252
  function authenticated() {
253
- return resolveAuthenticated({ load: loadSession, refresh: ensureAccess, remove: deleteSession, authorize: () => login("stable") });
253
+ return resolveAuthenticated({ load: loadSession, refresh: ensureAccess, remove: deleteSession });
254
254
  }
255
255
  async function logout() {
256
256
  let session;
@@ -302,10 +302,10 @@ import { dirname as dirname2, resolve } from "path";
302
302
  import { fileURLToPath } from "url";
303
303
 
304
304
  // src/solvea/commands.ts
305
- import { readFile as readFile4 } from "fs/promises";
305
+ import { readFile as readFile3 } from "fs/promises";
306
306
 
307
307
  // src/solvea/client.ts
308
- import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
308
+ import { mkdir, readFile, writeFile } from "fs/promises";
309
309
  import { basename, dirname, extname } from "path";
310
310
  import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
311
311
  var KNOWLEDGE_TYPES = /* @__PURE__ */ new Set(["QA", "LEARN_SELF", "FILE", "WEBSITE", "PRODUCT"]);
@@ -753,7 +753,7 @@ var SolveaClient = class {
753
753
  await client.send(new PutObjectCommand({
754
754
  Bucket: String(credentials.bucketName),
755
755
  Key: key,
756
- Body: await readFile2(filePath),
756
+ Body: await readFile(filePath),
757
757
  ContentType: contentTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream"
758
758
  }));
759
759
  return key;
@@ -770,8 +770,8 @@ var SolveaClient = class {
770
770
  signal: AbortSignal.timeout(3e4)
771
771
  });
772
772
  if (!response.ok) throw new Error(`HTTP ${response.status} GET ${path}: ${await response.text()}`);
773
- await mkdir2(dirname(target), { recursive: true });
774
- await writeFile2(target, new Uint8Array(await response.arrayBuffer()));
773
+ await mkdir(dirname(target), { recursive: true });
774
+ await writeFile(target, new Uint8Array(await response.arrayBuffer()));
775
775
  return target;
776
776
  }
777
777
  async downloadLabelTemplate(templateType, target) {
@@ -1013,10 +1013,10 @@ var SolveaClient = class {
1013
1013
  };
1014
1014
 
1015
1015
  // src/solvea/input.ts
1016
- import { readFile as readFile3 } from "fs/promises";
1016
+ import { readFile as readFile2 } from "fs/promises";
1017
1017
  async function jsonData(args, required = true) {
1018
1018
  const file = option(args, "--data-file");
1019
- const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
1019
+ const raw = file ? await readFile2(file, "utf8") : option(args, "--data");
1020
1020
  if (!raw) {
1021
1021
  if (required) throw new Error("--data or --data-file is required");
1022
1022
  return {};
@@ -1027,7 +1027,7 @@ async function jsonData(args, required = true) {
1027
1027
  }
1028
1028
  async function jsonValue(args) {
1029
1029
  const file = option(args, "--data-file");
1030
- const raw = file ? await readFile3(file, "utf8") : option(args, "--data", true);
1030
+ const raw = file ? await readFile2(file, "utf8") : option(args, "--data", true);
1031
1031
  return JSON.parse(raw);
1032
1032
  }
1033
1033
  function requireFlag(args, name, command) {
@@ -1210,7 +1210,7 @@ function enabled(args, command) {
1210
1210
  }
1211
1211
  async function data2(args) {
1212
1212
  const file = option(args, "--data-file");
1213
- const raw = file ? await readFile4(file, "utf8") : option(args, "--data");
1213
+ const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
1214
1214
  if (!raw) throw new Error("--data or --data-file is required");
1215
1215
  const parsed = JSON.parse(raw);
1216
1216
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("request data must be a JSON object");
@@ -1555,13 +1555,13 @@ async function runResourceCommand(session, resource, action2, args) {
1555
1555
 
1556
1556
  // src/doctor.ts
1557
1557
  import { access } from "fs/promises";
1558
- import { join as join2 } from "path";
1558
+ import { join } from "path";
1559
1559
  async function diagnose() {
1560
1560
  const root2 = packageRoot();
1561
1561
  const requiredFiles = [
1562
1562
  "package.json"
1563
1563
  ];
1564
- await Promise.all(requiredFiles.map((path) => access(join2(root2, path))));
1564
+ await Promise.all(requiredFiles.map((path) => access(join(root2, path))));
1565
1565
  const expectedPluginVersion = process.env.CXCLAW_PLUGIN_VERSION || null;
1566
1566
  if (expectedPluginVersion && expectedPluginVersion !== VERSION) {
1567
1567
  throw new Error(
@@ -1613,9 +1613,9 @@ function publicTenant(t) {
1613
1613
 
1614
1614
  // src/update.ts
1615
1615
  import { spawn } from "child_process";
1616
- import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1616
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
1617
1617
  import { homedir, platform } from "os";
1618
- import { isAbsolute, join as join3 } from "path";
1618
+ import { isAbsolute, join as join2 } from "path";
1619
1619
  var exec = (command, args, options3 = {}) => new Promise((resolve5, reject) => {
1620
1620
  const chunks = [];
1621
1621
  const child = spawn(command, args, {
@@ -1688,11 +1688,11 @@ async function update() {
1688
1688
  async function installScheduler() {
1689
1689
  const invocation = schedulerInvocation();
1690
1690
  if (platform() === "darwin") {
1691
- const dir = join3(homedir(), "Library/LaunchAgents");
1692
- 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");
1693
1693
  const programArguments = [invocation.command, ...invocation.args].map((value) => `<string>${xml(value)}</string>`).join("");
1694
- await mkdir3(dir, { recursive: true });
1695
- await writeFile3(
1694
+ await mkdir2(dir, { recursive: true });
1695
+ await writeFile2(
1696
1696
  path,
1697
1697
  `<?xml version="1.0" encoding="UTF-8"?>
1698
1698
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -1704,18 +1704,18 @@ async function installScheduler() {
1704
1704
  return;
1705
1705
  }
1706
1706
  if (platform() === "linux") {
1707
- const dir = join3(homedir(), ".config/systemd/user");
1707
+ const dir = join2(homedir(), ".config/systemd/user");
1708
1708
  const command = [invocation.command, ...invocation.args].map(systemdArg).join(" ");
1709
- await mkdir3(dir, { recursive: true });
1710
- await writeFile3(
1711
- join3(dir, "cxclaw-update.service"),
1709
+ await mkdir2(dir, { recursive: true });
1710
+ await writeFile2(
1711
+ join2(dir, "cxclaw-update.service"),
1712
1712
  `[Service]
1713
1713
  Type=oneshot
1714
1714
  ExecStart=${command}
1715
1715
  `
1716
1716
  );
1717
- await writeFile3(
1718
- join3(dir, "cxclaw-update.timer"),
1717
+ await writeFile2(
1718
+ join2(dir, "cxclaw-update.timer"),
1719
1719
  "[Timer]\nOnBootSec=5m\nOnUnitActiveSec=6h\nPersistent=true\n[Install]\nWantedBy=timers.target\n"
1720
1720
  );
1721
1721
  await exec("systemctl", ["--user", "daemon-reload"]);
@@ -1754,12 +1754,12 @@ async function installMarketplace(channel) {
1754
1754
  // src/workflows/runtime.ts
1755
1755
  import { execFile } from "child_process";
1756
1756
  import { promises as fs } from "fs";
1757
- import { join as join4, resolve as resolve2 } from "path";
1757
+ import { join as join3, resolve as resolve2 } from "path";
1758
1758
  import { promisify } from "util";
1759
1759
  var exec2 = promisify(execFile);
1760
- var workspace = () => resolve2(process.env.WORKSPACE_DIR ?? join4(process.cwd(), "workspace"));
1761
- var root = () => join4(workspace(), "runtime-inspector");
1762
- 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") });
1763
1763
  var timestamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1764
1764
  var readJson = async (path, fallback) => {
1765
1765
  try {
@@ -1795,26 +1795,26 @@ async function prepare(args) {
1795
1795
  await fs.mkdir(tmp, { recursive: true });
1796
1796
  const batches = [];
1797
1797
  for (let i = 0; i < records.length; i += batchSize) batches.push(records.slice(i, i + batchSize));
1798
- await Promise.all(batches.map((batch, i) => writeJson(join4(tmp, `batch_${String(i).padStart(3, "0")}.json`), batch)));
1799
- 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() });
1800
1800
  return { status: "batched", totalRecords: records.length, totalBatches: batches.length, tmp };
1801
1801
  }
1802
1802
  async function processBatches() {
1803
1803
  const { tmp, output, state: state2 } = dirs();
1804
- const current = await readJson(join4(state2, "inspect.json"), {});
1804
+ const current = await readJson(join3(state2, "inspect.json"), {});
1805
1805
  if (current.status !== "batched") throw new Error(`runtime state must be batched, got ${String(current.status ?? "missing")}`);
1806
1806
  const names = (await fs.readdir(tmp)).filter((name) => /^batch_\d+\.json$/.test(name)).sort();
1807
1807
  if (!names.length) throw new Error(`no batch files found in ${tmp}`);
1808
1808
  const records = [];
1809
- 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() });
1810
- 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`);
1811
1811
  await writeJson(path, { total: records.length, processed_at: (/* @__PURE__ */ new Date()).toISOString(), source: current.source, records });
1812
- 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() });
1813
1813
  return { status: "done", total: records.length, resultsPath: path };
1814
1814
  }
1815
1815
  async function state() {
1816
1816
  const { state: stateDir2, output, tmp } = dirs();
1817
- 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(() => []) };
1818
1818
  }
1819
1819
  async function verify() {
1820
1820
  const snapshot = await state();
@@ -1841,7 +1841,7 @@ async function sandbox(args) {
1841
1841
  }
1842
1842
  async function model(args) {
1843
1843
  if (option(args, "--scenario", true) !== "truncation") throw new Error("only --scenario truncation is supported");
1844
- const target = join4(dirs().tmp, "truncation_test.md");
1844
+ const target = join3(dirs().tmp, "truncation_test.md");
1845
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." };
1846
1846
  }
1847
1847
  async function runRuntime(action2, args) {
@@ -1854,9 +1854,9 @@ async function runRuntime(action2, args) {
1854
1854
  if (action2 === "write-test") {
1855
1855
  const { output, state: stateDir2 } = dirs();
1856
1856
  const runId = timestamp();
1857
- await writeJson(join4(output, `${runId}_test.json`), { run_id: runId, written_at: (/* @__PURE__ */ new Date()).toISOString() });
1858
- const current = await readJson(join4(stateDir2, "inspect.json"), {});
1859
- 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 });
1860
1860
  return { ok: true, runId };
1861
1861
  }
1862
1862
  throw new Error("runtime action must be prepare, process, state, verify, sandbox, model, or write-test");
@@ -1865,10 +1865,10 @@ async function runRuntime(action2, args) {
1865
1865
  // src/workflows/solvea-kit.ts
1866
1866
  import ExcelJS from "exceljs";
1867
1867
  import { promises as fs2 } from "fs";
1868
- import { dirname as dirname3, join as join5, resolve as resolve3 } from "path";
1869
- var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ?? join5(process.cwd(), "workspace"));
1870
- var outputDir = (owner) => join5(workspace2(), "outputs", owner);
1871
- 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);
1872
1872
  var now = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1873
1873
  var readJson2 = async (path) => JSON.parse(await fs2.readFile(path, "utf8"));
1874
1874
  var writeJson2 = async (path, value) => {
@@ -1898,7 +1898,7 @@ function labelsFrom(value) {
1898
1898
  async function generateLabelImport(args) {
1899
1899
  const input = option(args, "--input") ?? option(args, "--data-file", true);
1900
1900
  const init = args.includes("--init");
1901
- 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");
1902
1902
  const labels = labelsFrom(await readJson2(input));
1903
1903
  const workbook = new ExcelJS.Workbook();
1904
1904
  const sheet = workbook.addWorksheet("labels");
@@ -1938,9 +1938,9 @@ async function classifyIntents(args) {
1938
1938
  if (!noExcel && !option(args, "--xlsx")) throw new Error("provide --xlsx or --no-excel");
1939
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 }));
1940
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: [] };
1941
- const resultPath = join5(outputDir(owner), `results_${runId}.json`);
1941
+ const resultPath = join4(outputDir(owner), `results_${runId}.json`);
1942
1942
  await writeJson2(resultPath, result);
1943
- 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() });
1944
1944
  return { ...result.meta, resultsPath: resultPath };
1945
1945
  }
1946
1946
  async function runSolveaKitWorkflow(action2, args) {
@@ -1950,7 +1950,7 @@ async function runSolveaKitWorkflow(action2, args) {
1950
1950
  }
1951
1951
 
1952
1952
  // src/workflows/support.ts
1953
- import { readFile as readFile5 } from "fs/promises";
1953
+ import { readFile as readFile4 } from "fs/promises";
1954
1954
  import { basename as basename3 } from "path";
1955
1955
  var safe = (value) => encodeURIComponent(value);
1956
1956
  var docsMcpUrl = process.env.CXCLAW_DOCS_MCP_URL ?? "https://solvea-39f11a36.mintlify.app/mcp";
@@ -2025,7 +2025,7 @@ async function runSupport(session, action2, args) {
2025
2025
  const attachments = [];
2026
2026
  for (const file of options2(args, "--attachment")) {
2027
2027
  const form = new FormData();
2028
- form.append("file", new Blob([await readFile5(file)]), basename3(file));
2028
+ form.append("file", new Blob([await readFile4(file)]), basename3(file));
2029
2029
  const tenant = session.tenant;
2030
2030
  const base = tenant?.businessUrl?.replace(/\/$/, "");
2031
2031
  if (!tenant || !base || !tenant.businessToken) throw new Error("no tenant selected");
@@ -2056,24 +2056,24 @@ async function runSupport(session, action2, args) {
2056
2056
  }
2057
2057
 
2058
2058
  // src/workflows/common.ts
2059
- import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
2060
- 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";
2061
2061
  import { homedir as homedir2 } from "os";
2062
- var workspaceRoot = () => resolve4(process.env.CXCLAW_WORKSPACE ?? join6(homedir2(), ".cxclaw", "workspace"));
2063
- var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ?? join6(workspaceRoot(), "state"), domain);
2064
- 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);
2065
2065
  async function ensureParent(file) {
2066
- await mkdir4(dirname4(file), { recursive: true });
2066
+ await mkdir3(dirname4(file), { recursive: true });
2067
2067
  }
2068
2068
  async function ensureDir(directory) {
2069
- await mkdir4(directory, { recursive: true });
2069
+ await mkdir3(directory, { recursive: true });
2070
2070
  }
2071
2071
  async function readJson3(file) {
2072
- return JSON.parse(await readFile6(file, "utf8"));
2072
+ return JSON.parse(await readFile5(file, "utf8"));
2073
2073
  }
2074
2074
  async function writeJson3(file, value) {
2075
2075
  await ensureParent(file);
2076
- await writeFile4(file, `${JSON.stringify(value, null, 2)}
2076
+ await writeFile3(file, `${JSON.stringify(value, null, 2)}
2077
2077
  `, "utf8");
2078
2078
  }
2079
2079
  function intOption(args, name, fallback) {
@@ -2091,7 +2091,7 @@ function htmlEscape(value) {
2091
2091
  }
2092
2092
  async function writeHtml(file, title, body) {
2093
2093
  await ensureParent(file);
2094
- 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");
2095
2095
  }
2096
2096
  function asRows(value) {
2097
2097
  if (Array.isArray(value)) return value.filter((item) => item && typeof item === "object");
@@ -2298,13 +2298,13 @@ async function runLocalAgentWorkflow(action2, args) {
2298
2298
  }
2299
2299
  async function writeFileText(file, content) {
2300
2300
  await ensureParent(file);
2301
- const { writeFile: writeFile5 } = await import("fs/promises");
2302
- await writeFile5(file, `${content}
2301
+ const { writeFile: writeFile4 } = await import("fs/promises");
2302
+ await writeFile4(file, `${content}
2303
2303
  `, "utf8");
2304
2304
  }
2305
2305
 
2306
2306
  // src/workflows/tester.ts
2307
- import { join as join7 } from "path";
2307
+ import { join as join6 } from "path";
2308
2308
  import ExcelJS2 from "exceljs";
2309
2309
  async function casesFrom(file) {
2310
2310
  if (file.endsWith(".json")) return asRows(await readJson3(file));
@@ -2326,7 +2326,7 @@ async function casesFrom(file) {
2326
2326
  }
2327
2327
  async function createSheet(args) {
2328
2328
  const cases = option(args, "--cases-file") ? await casesFrom(option(args, "--cases-file")) : [];
2329
- 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`);
2330
2330
  await ensureParent(output);
2331
2331
  const workbook = new ExcelJS2.Workbook();
2332
2332
  const sheet = workbook.addWorksheet("cases");
@@ -2352,7 +2352,7 @@ async function runAgentTester(session, action2, args) {
2352
2352
  }
2353
2353
 
2354
2354
  // src/workflows/delivery.ts
2355
- import { join as join8 } from "path";
2355
+ import { join as join7 } from "path";
2356
2356
  import ExcelJS3 from "exceljs";
2357
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"];
2358
2358
  async function loadRows(file) {
@@ -2386,7 +2386,7 @@ async function writeRows(file, rows) {
2386
2386
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2387
2387
  sheet.addRow(keys);
2388
2388
  rows.forEach((row) => sheet.addRow(keys.map((key) => row[key] ?? "")));
2389
- await ensureDir(join8(file, ".."));
2389
+ await ensureDir(join7(file, ".."));
2390
2390
  await workbook.xlsx.writeFile(file);
2391
2391
  }
2392
2392
  function classify(text) {
@@ -2407,13 +2407,13 @@ async function classifyCases(args, domain) {
2407
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" }));
2408
2408
  const runId = option(args, "--run-id") ?? Date.now().toString();
2409
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) };
2410
- const out = option(args, "--results") ?? join8(outputRoot(domain), `results_${runId}.json`);
2410
+ const out = option(args, "--results") ?? join7(outputRoot(domain), `results_${runId}.json`);
2411
2411
  await writeJson3(out, result);
2412
- 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() });
2413
2413
  return { ...result.meta, resultsPath: out };
2414
2414
  }
2415
2415
  async function plan(domain, args) {
2416
- const file = join8(stateRoot(domain), "progress.json");
2416
+ const file = join7(stateRoot(domain), "progress.json");
2417
2417
  let current = {};
2418
2418
  try {
2419
2419
  current = await readJson3(file);
@@ -2437,7 +2437,7 @@ async function plan(domain, args) {
2437
2437
  async function runBatch(client, args, domain) {
2438
2438
  const input = option(args, "--input") ?? option(args, "--test-file", true);
2439
2439
  const rows = await loadRows(input);
2440
- 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`);
2441
2441
  const workers = Math.max(1, Math.min(intOption(args, "--workers", 4), 16));
2442
2442
  const results = [];
2443
2443
  let cursor = 0;
@@ -2461,7 +2461,7 @@ async function runBatch(client, args, domain) {
2461
2461
  return { output, total: results.length, succeeded: results.filter((row) => row.ok).length, failed: results.filter((row) => !row.ok).length };
2462
2462
  }
2463
2463
  async function createAgents(client, args, domain) {
2464
- const state2 = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2464
+ const state2 = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2465
2465
  const resultsPath = option(args, "--results") ?? (typeof state2.results_path === "string" ? state2.results_path : void 0);
2466
2466
  if (!resultsPath) throw new Error("classification results are required");
2467
2467
  const result = await readJson3(resultsPath);
@@ -2472,12 +2472,12 @@ async function createAgents(client, args, domain) {
2472
2472
  return { created, count: created.length };
2473
2473
  }
2474
2474
  async function renderReport(args, domain) {
2475
- const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2475
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2476
2476
  const resultsFile = option(args, "--results") ?? option(args, "--input") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2477
2477
  if (!resultsFile) throw new Error("--results/--input is required, or run classify first");
2478
2478
  const value = await readJson3(resultsFile);
2479
2479
  const rows = asRows(value.results ?? value.items ?? value);
2480
- 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`);
2481
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("")}`;
2482
2482
  await writeHtml(output, option(args, "--title") ?? `${domain} report`, body);
2483
2483
  const md = option(args, "--md");
@@ -2488,12 +2488,12 @@ Total: ${rows.length}
2488
2488
  return { output, count: rows.length };
2489
2489
  }
2490
2490
  async function genExcel(args, domain) {
2491
- const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2491
+ const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2492
2492
  const input = option(args, "--results") ?? option(args, "--items") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2493
2493
  if (!input) throw new Error("--results or --items is required, or run classify first");
2494
2494
  const value = await readJson3(input);
2495
2495
  const rows = asRows(value);
2496
- const output = option(args, "--output") ?? join8(outputRoot(domain), `${domain}_results.xlsx`);
2496
+ const output = option(args, "--output") ?? join7(outputRoot(domain), `${domain}_results.xlsx`);
2497
2497
  await writeRows(output, rows);
2498
2498
  return { output, count: rows.length };
2499
2499
  }
@@ -2533,7 +2533,7 @@ async function runDomain(session, domain, action2, args) {
2533
2533
  }
2534
2534
 
2535
2535
  // src/workflows/kb-builder.ts
2536
- import { join as join9 } from "path";
2536
+ import { join as join8 } from "path";
2537
2537
  import ExcelJS4 from "exceljs";
2538
2538
  var clean = (value) => String(value ?? "").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
2539
2539
  var absolute = (href, base) => {
@@ -2567,7 +2567,7 @@ async function crawl(args) {
2567
2567
  }
2568
2568
  }
2569
2569
  const result = { url, mode: option(args, "--mode") ?? "auto", pages, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), total: pages.length };
2570
- 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");
2571
2571
  await writeJson3(output, result);
2572
2572
  return { ...result, output };
2573
2573
  }
@@ -2582,13 +2582,13 @@ async function directoryPlan(args) {
2582
2582
  }
2583
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 })) }));
2584
2584
  const result = { source: option(args, "--crawl-result"), generatedAt: (/* @__PURE__ */ new Date()).toISOString(), tree, confirmed: false };
2585
- 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");
2586
2586
  await writeJson3(output, result);
2587
- 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 });
2588
2588
  return { output, directories: tree.length, pages: rows.length, tree };
2589
2589
  }
2590
2590
  async function createDirectories(client, args) {
2591
- 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");
2592
2592
  const value = await readJson3(file);
2593
2593
  const tree = Array.isArray(value.tree) ? value.tree : Array.isArray(value) ? value : [];
2594
2594
  if (!tree.length) throw new Error("confirmed directory tree is empty");
@@ -2611,12 +2611,12 @@ async function createDirectories(client, args) {
2611
2611
  async function extractWebQa(args) {
2612
2612
  const input = await readJson3(option(args, "--crawl-result", true));
2613
2613
  const pages = asRows(input.pages ?? input).slice(0, intOption(args, "--max-pages", 80));
2614
- 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");
2615
2615
  await ensureDir(outputDir2);
2616
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 }));
2617
2617
  const files = [];
2618
2618
  for (const [index, part] of parts.entries()) {
2619
- 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`);
2620
2620
  await writeJson3(file, { items: [part] });
2621
2621
  files.push(file);
2622
2622
  }
@@ -2682,9 +2682,9 @@ async function importQa(client, args) {
2682
2682
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2683
2683
  }
2684
2684
  if (fromDir) {
2685
- const { readdir: readdir2 } = await import("fs/promises");
2686
- for (const file of (await readdir2(fromDir)).filter((name) => name.endsWith(".json")).sort()) {
2687
- 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));
2688
2688
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2689
2689
  }
2690
2690
  }
@@ -2692,7 +2692,7 @@ async function importQa(client, args) {
2692
2692
  if (!Number.isSafeInteger(maxDepth) || maxDepth <= 0) throw new Error("--max-depth must be a positive integer");
2693
2693
  const normalized = validateQaItems(items, maxDepth);
2694
2694
  const plan2 = { items, count: items.length, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
2695
- 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`);
2696
2696
  await writeJson3(planFile, plan2);
2697
2697
  if (flag(args, "--dry-run")) return { dryRun: true, planFile, count: items.length };
2698
2698
  const directories = flattenDirectories(asRows(await client.listDirectories()));
@@ -2767,7 +2767,7 @@ async function importTemplates(client, args) {
2767
2767
  });
2768
2768
  }
2769
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);
2770
- 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`);
2771
2771
  await writeJson3(output, { items, count: items.length });
2772
2772
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
2773
2773
  const results = [];
@@ -2782,13 +2782,13 @@ async function exportKnowledge(client, args) {
2782
2782
  const value = await client.listKnowledge({ directoryId: id, keyword: option(args, "--keyword") ?? "", type: option(args, "--type") ?? "ALL", pageSize: intOption(args, "--page-size", 1e3) });
2783
2783
  rows.push(...asRows(value).map((row) => ({ ...row, directoryId: id, directoryName: directories.find((dir) => Number(dir.id ?? dir.directoryId) === id)?.name ?? "" })));
2784
2784
  }
2785
- 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`);
2786
2786
  const workbook = new ExcelJS4.Workbook();
2787
2787
  const sheet = workbook.addWorksheet("knowledge");
2788
2788
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2789
2789
  sheet.addRow(keys);
2790
2790
  for (const row of rows) sheet.addRow(keys.map((key) => row[key] ?? ""));
2791
- await ensureDir(join9(output, ".."));
2791
+ await ensureDir(join8(output, ".."));
2792
2792
  await workbook.xlsx.writeFile(output);
2793
2793
  return { output, count: rows.length };
2794
2794
  }
@@ -2829,7 +2829,7 @@ async function extractTicketQa(args) {
2829
2829
  const answer = String(record[replyCol] ?? "").trim();
2830
2830
  if (question && question !== `${brand}:`) items.push({ question, answer, sourceRow: number });
2831
2831
  });
2832
- 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`);
2833
2833
  const result = { brand, count: items.length, items };
2834
2834
  await writeJson3(output, result);
2835
2835
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
@@ -2837,12 +2837,12 @@ async function extractTicketQa(args) {
2837
2837
  }
2838
2838
 
2839
2839
  // src/workflows/desk.ts
2840
- import { join as join10 } from "path";
2840
+ import { join as join9 } from "path";
2841
2841
  import ExcelJS5 from "exceljs";
2842
2842
  var taskId = (args) => option(args, "--task-id") ?? (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
2843
- var taskDir = (args) => join10(stateRoot("solvea-desk"), taskId(args));
2843
+ var taskDir = (args) => join9(stateRoot("solvea-desk"), taskId(args));
2844
2844
  async function saveDatasource(dir, name, rows) {
2845
- const file = join10(dir, name);
2845
+ const file = join9(dir, name);
2846
2846
  await ensureParent(file);
2847
2847
  const workbook = new ExcelJS5.Workbook();
2848
2848
  const sheet = workbook.addWorksheet("data");
@@ -2865,7 +2865,7 @@ async function fetchTickets(client, args) {
2865
2865
  if (pageRows.length < pageSize2) break;
2866
2866
  }
2867
2867
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2868
- 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 });
2869
2869
  return { taskId: taskId(args), output, count: rows.length };
2870
2870
  }
2871
2871
  async function fetchSources(client, args) {
@@ -2876,7 +2876,7 @@ async function fetchSources(client, args) {
2876
2876
  const rows = asRows(value).slice(0, intOption(args, "--max-rows", 1e4));
2877
2877
  sources.tickets = rows;
2878
2878
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2879
- await writeJson3(join10(dir, "sources.json"), sources);
2879
+ await writeJson3(join9(dir, "sources.json"), sources);
2880
2880
  return { taskId: taskId(args), output, count: rows.length };
2881
2881
  }
2882
2882
  async function tags(client, action2, args) {
@@ -2903,10 +2903,10 @@ async function tags(client, action2, args) {
2903
2903
  throw new Error(`unknown tag action: ${action2}`);
2904
2904
  }
2905
2905
  async function renderReport2(args) {
2906
- 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");
2907
2907
  const data3 = await readJson3(dataFile);
2908
2908
  if (flag(args, "--validate-only")) return { valid: true, dataFile };
2909
- 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`);
2910
2910
  const body = `<pre>${htmlEscape(JSON.stringify({ data: data3, notes: await readJson3(notesFile).catch(() => ({})) }, null, 2))}</pre>`;
2911
2911
  await writeHtml(output, option(args, "--report-slug") ?? "Solvea Desk report", body);
2912
2912
  return { output, valid: true };
@@ -2937,7 +2937,6 @@ async function runAuth(action2, args) {
2937
2937
  const session = await login(option(args, "--channel") ?? "stable");
2938
2938
  return print(publicAuthStatus(session));
2939
2939
  }
2940
- if (action2 === "ensure") return print(publicAuthStatus(await authenticated()));
2941
2940
  if (action2 === "logout") {
2942
2941
  await logout();
2943
2942
  return print({ ok: true, loggedOut: true });
@@ -2953,7 +2952,7 @@ async function runAuth(action2, args) {
2953
2952
  if (action2 === "refresh") {
2954
2953
  return print(publicAuthStatus(await authenticated()));
2955
2954
  }
2956
- 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");
2957
2956
  }
2958
2957
  async function runTenant(action2, args) {
2959
2958
  const session = await authenticated();
@@ -3026,11 +3025,12 @@ async function main(args = process.argv.slice(2)) {
3026
3025
  if (flag(args, "--scheduled")) await new Promise((resolve5) => setTimeout(resolve5, Math.random() * 18e5));
3027
3026
  return print(await update());
3028
3027
  }
3029
- 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"));
3030
3029
  else throw new Error(`unknown command: ${command}`);
3031
3030
  }
3032
3031
  main().catch((error) => {
3033
- console.error(`cxclawctl: ${error instanceof Error ? error.message : String(error)}`);
3034
- process.exitCode = 1;
3032
+ const output = errorOutput(error);
3033
+ console.error(JSON.stringify(output));
3034
+ process.exitCode = output.error.code;
3035
3035
  });
3036
3036
  //# sourceMappingURL=cli.js.map