@shulex/cxclawctl 0.1.9 → 0.1.11

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 readFile6 } from "fs/promises";
4
+ import { readFile as readFile7 } 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.9",
15
+ version: "0.1.11",
16
16
  description: "Solvea CXClaw CLI and Codex plugin runtime",
17
17
  type: "module",
18
18
  bin: {
@@ -22,6 +22,7 @@ var package_default = {
22
22
  "bin",
23
23
  "dist/cli.js",
24
24
  "dist/cli.js.map",
25
+ "runtime",
25
26
  "capabilities.lock.json"
26
27
  ],
27
28
  scripts: {
@@ -33,6 +34,7 @@ var package_default = {
33
34
  "check:release": "tsx scripts/check-release.ts",
34
35
  "test:package": "tsx scripts/test-packed-package.ts",
35
36
  "release:prepare": "tsx scripts/prepare-release.ts",
37
+ "release:create": "tsx scripts/create-release.ts",
36
38
  "package:agent-plugin": "node scripts/package-agent-plugin.mjs",
37
39
  "package:codex-plugin": "node scripts/package-codex-plugin.mjs"
38
40
  },
@@ -131,40 +133,82 @@ async function deleteSession() {
131
133
  await entry().deleteCredential();
132
134
  }
133
135
 
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
+ }
160
+ }
161
+
134
162
  // src/auth.ts
135
163
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
136
164
  var loginInFlight;
137
165
  function publicAuthStatus(session) {
138
166
  return { ok: true, loggedIn: true, email: session.email, channel: session.channel, accessExpiresAt: session.accessExpiry };
139
167
  }
140
- async function runLogin(channel) {
168
+ async function authorizeDevice(channel, runtime) {
141
169
  const session = { channel, accessToken: "", refreshToken: "", accessExpiry: 0, employeeId: "", email: "" };
142
- const start = await post(session, "/auth/device/start", { clientVersion: VERSION });
143
- console.error(`\u8BF7\u5728\u6D4F\u89C8\u5668\u6253\u5F00\u4EE5\u4E0B\u5730\u5740\u5B8C\u6210\u9489\u9489\u6388\u6743\uFF1A
170
+ const start = await runtime.start(session);
171
+ try {
172
+ await runtime.openBrowser(start.verificationUriComplete);
173
+ runtime.log("\u9489\u9489\u6388\u6743\u9875\u5DF2\u6253\u5F00\uFF0C\u5F53\u524D\u547D\u4EE4\u4F1A\u6301\u7EED\u7B49\u5F85\u6388\u6743\u7ED3\u679C\uFF0C\u65E0\u9700\u56DE\u590D Codex\u3002");
174
+ } catch {
175
+ runtime.log(`\u672A\u80FD\u81EA\u52A8\u6253\u5F00\u6D4F\u89C8\u5668\uFF0C\u8BF7\u6253\u5F00\u4EE5\u4E0B\u5730\u5740\u5B8C\u6210\u9489\u9489\u6388\u6743\uFF1A
144
176
  ${start.verificationUriComplete}
145
177
  \u8BBE\u5907\u7801\uFF1A${start.userCode}`);
146
- await open(start.verificationUriComplete).catch(() => void 0);
147
- const deadline = Date.now() + start.expiresIn * 1e3;
148
- console.error("\u6B63\u5728\u7B49\u5F85\u9489\u9489\u6388\u6743\uFF0C\u6388\u6743\u5B8C\u6210\u540E\u5F53\u524D\u547D\u4EE4\u4F1A\u81EA\u52A8\u7EE7\u7EED\uFF0C\u65E0\u9700\u56DE\u590D Codex\u3002");
149
- let nextProgressAt = Date.now() + 15e3;
150
- while (Date.now() < deadline) {
151
- await sleep(Math.max(2, start.interval) * 1e3);
178
+ }
179
+ const deadline = runtime.now() + start.expiresIn * 1e3;
180
+ let nextProgressAt = runtime.now() + 15e3;
181
+ while (runtime.now() < deadline) {
182
+ await runtime.sleep(Math.max(2, start.interval) * 1e3);
152
183
  try {
153
- const token = await post(session, "/auth/device/token", { deviceCode: start.deviceCode, clientVersion: VERSION });
154
- Object.assign(session, { accessToken: token.accessToken, refreshToken: token.refreshToken, accessExpiry: Math.floor(Date.now() / 1e3) + token.expiresIn, employeeId: token.employee.id, email: token.employee.email });
155
- await saveSession(session);
156
- console.error("\u9489\u9489\u6388\u6743\u6210\u529F\uFF0C\u7EE7\u7EED\u6267\u884C\u5F53\u524D\u547D\u4EE4\u3002");
184
+ const token = await runtime.poll(session, start.deviceCode);
185
+ 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
+ await runtime.save(session);
187
+ runtime.log("\u9489\u9489\u6388\u6743\u6210\u529F\uFF0C\u7EE7\u7EED\u6267\u884C\u5F53\u524D\u547D\u4EE4\u3002");
157
188
  return session;
158
189
  } catch (error) {
159
190
  if (!(error instanceof HttpError) || error.status !== 428) throw error;
160
- if (Date.now() >= nextProgressAt) {
161
- console.error("\u4ECD\u5728\u7B49\u5F85\u9489\u9489\u6388\u6743\u2026\u2026");
162
- nextProgressAt = Date.now() + 15e3;
191
+ if (runtime.now() >= nextProgressAt) {
192
+ runtime.log("\u4ECD\u5728\u7B49\u5F85\u9489\u9489\u6388\u6743\u2026\u2026");
193
+ nextProgressAt = runtime.now() + 15e3;
163
194
  }
164
195
  }
165
196
  }
166
197
  throw new Error("device authorization expired");
167
198
  }
199
+ async function runLogin(channel) {
200
+ return withAuthWaitMarker(() => authorizeDevice(channel, {
201
+ start: (session) => post(session, "/auth/device/start", { clientVersion: VERSION }),
202
+ poll: (session, deviceCode) => post(session, "/auth/device/token", { deviceCode, clientVersion: VERSION }),
203
+ openBrowser: async (url) => {
204
+ await open(url);
205
+ },
206
+ save: saveSession,
207
+ sleep,
208
+ now: Date.now,
209
+ log: (message) => console.error(message)
210
+ }));
211
+ }
168
212
  function login(channel) {
169
213
  if (!loginInFlight) loginInFlight = runLogin(channel).finally(() => {
170
214
  loginInFlight = void 0;
@@ -247,10 +291,10 @@ import { dirname as dirname2, resolve } from "path";
247
291
  import { fileURLToPath } from "url";
248
292
 
249
293
  // src/solvea/commands.ts
250
- import { readFile as readFile3 } from "fs/promises";
294
+ import { readFile as readFile4 } from "fs/promises";
251
295
 
252
296
  // src/solvea/client.ts
253
- import { mkdir, readFile, writeFile } from "fs/promises";
297
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
254
298
  import { basename, dirname, extname } from "path";
255
299
  import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
256
300
  var KNOWLEDGE_TYPES = /* @__PURE__ */ new Set(["QA", "LEARN_SELF", "FILE", "WEBSITE", "PRODUCT"]);
@@ -698,7 +742,7 @@ var SolveaClient = class {
698
742
  await client.send(new PutObjectCommand({
699
743
  Bucket: String(credentials.bucketName),
700
744
  Key: key,
701
- Body: await readFile(filePath),
745
+ Body: await readFile2(filePath),
702
746
  ContentType: contentTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream"
703
747
  }));
704
748
  return key;
@@ -715,8 +759,8 @@ var SolveaClient = class {
715
759
  signal: AbortSignal.timeout(3e4)
716
760
  });
717
761
  if (!response.ok) throw new Error(`HTTP ${response.status} GET ${path}: ${await response.text()}`);
718
- await mkdir(dirname(target), { recursive: true });
719
- await writeFile(target, new Uint8Array(await response.arrayBuffer()));
762
+ await mkdir2(dirname(target), { recursive: true });
763
+ await writeFile2(target, new Uint8Array(await response.arrayBuffer()));
720
764
  return target;
721
765
  }
722
766
  async downloadLabelTemplate(templateType, target) {
@@ -958,10 +1002,10 @@ var SolveaClient = class {
958
1002
  };
959
1003
 
960
1004
  // src/solvea/input.ts
961
- import { readFile as readFile2 } from "fs/promises";
1005
+ import { readFile as readFile3 } from "fs/promises";
962
1006
  async function jsonData(args, required = true) {
963
1007
  const file = option(args, "--data-file");
964
- const raw = file ? await readFile2(file, "utf8") : option(args, "--data");
1008
+ const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
965
1009
  if (!raw) {
966
1010
  if (required) throw new Error("--data or --data-file is required");
967
1011
  return {};
@@ -972,7 +1016,7 @@ async function jsonData(args, required = true) {
972
1016
  }
973
1017
  async function jsonValue(args) {
974
1018
  const file = option(args, "--data-file");
975
- const raw = file ? await readFile2(file, "utf8") : option(args, "--data", true);
1019
+ const raw = file ? await readFile3(file, "utf8") : option(args, "--data", true);
976
1020
  return JSON.parse(raw);
977
1021
  }
978
1022
  function requireFlag(args, name, command) {
@@ -1155,7 +1199,7 @@ function enabled(args, command) {
1155
1199
  }
1156
1200
  async function data2(args) {
1157
1201
  const file = option(args, "--data-file");
1158
- const raw = file ? await readFile3(file, "utf8") : option(args, "--data");
1202
+ const raw = file ? await readFile4(file, "utf8") : option(args, "--data");
1159
1203
  if (!raw) throw new Error("--data or --data-file is required");
1160
1204
  const parsed = JSON.parse(raw);
1161
1205
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("request data must be a JSON object");
@@ -1500,13 +1544,13 @@ async function runResourceCommand(session, resource, action2, args) {
1500
1544
 
1501
1545
  // src/doctor.ts
1502
1546
  import { access } from "fs/promises";
1503
- import { join } from "path";
1547
+ import { join as join2 } from "path";
1504
1548
  async function diagnose() {
1505
1549
  const root2 = packageRoot();
1506
1550
  const requiredFiles = [
1507
1551
  "package.json"
1508
1552
  ];
1509
- await Promise.all(requiredFiles.map((path) => access(join(root2, path))));
1553
+ await Promise.all(requiredFiles.map((path) => access(join2(root2, path))));
1510
1554
  const expectedPluginVersion = process.env.CXCLAW_PLUGIN_VERSION || null;
1511
1555
  if (expectedPluginVersion && expectedPluginVersion !== VERSION) {
1512
1556
  throw new Error(
@@ -1558,9 +1602,9 @@ function publicTenant(t) {
1558
1602
 
1559
1603
  // src/update.ts
1560
1604
  import { spawn } from "child_process";
1561
- import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
1605
+ import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
1562
1606
  import { homedir, platform } from "os";
1563
- import { isAbsolute, join as join2 } from "path";
1607
+ import { isAbsolute, join as join3 } from "path";
1564
1608
  var exec = (command, args, options3 = {}) => new Promise((resolve5, reject) => {
1565
1609
  const chunks = [];
1566
1610
  const child = spawn(command, args, {
@@ -1633,11 +1677,11 @@ async function update() {
1633
1677
  async function installScheduler() {
1634
1678
  const invocation = schedulerInvocation();
1635
1679
  if (platform() === "darwin") {
1636
- const dir = join2(homedir(), "Library/LaunchAgents");
1637
- const path = join2(dir, "com.solvea.cxclaw.update.plist");
1680
+ const dir = join3(homedir(), "Library/LaunchAgents");
1681
+ const path = join3(dir, "com.solvea.cxclaw.update.plist");
1638
1682
  const programArguments = [invocation.command, ...invocation.args].map((value) => `<string>${xml(value)}</string>`).join("");
1639
- await mkdir2(dir, { recursive: true });
1640
- await writeFile2(
1683
+ await mkdir3(dir, { recursive: true });
1684
+ await writeFile3(
1641
1685
  path,
1642
1686
  `<?xml version="1.0" encoding="UTF-8"?>
1643
1687
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -1649,18 +1693,18 @@ async function installScheduler() {
1649
1693
  return;
1650
1694
  }
1651
1695
  if (platform() === "linux") {
1652
- const dir = join2(homedir(), ".config/systemd/user");
1696
+ const dir = join3(homedir(), ".config/systemd/user");
1653
1697
  const command = [invocation.command, ...invocation.args].map(systemdArg).join(" ");
1654
- await mkdir2(dir, { recursive: true });
1655
- await writeFile2(
1656
- join2(dir, "cxclaw-update.service"),
1698
+ await mkdir3(dir, { recursive: true });
1699
+ await writeFile3(
1700
+ join3(dir, "cxclaw-update.service"),
1657
1701
  `[Service]
1658
1702
  Type=oneshot
1659
1703
  ExecStart=${command}
1660
1704
  `
1661
1705
  );
1662
- await writeFile2(
1663
- join2(dir, "cxclaw-update.timer"),
1706
+ await writeFile3(
1707
+ join3(dir, "cxclaw-update.timer"),
1664
1708
  "[Timer]\nOnBootSec=5m\nOnUnitActiveSec=6h\nPersistent=true\n[Install]\nWantedBy=timers.target\n"
1665
1709
  );
1666
1710
  await exec("systemctl", ["--user", "daemon-reload"]);
@@ -1699,12 +1743,12 @@ async function installMarketplace(channel) {
1699
1743
  // src/workflows/runtime.ts
1700
1744
  import { execFile } from "child_process";
1701
1745
  import { promises as fs } from "fs";
1702
- import { join as join3, resolve as resolve2 } from "path";
1746
+ import { join as join4, resolve as resolve2 } from "path";
1703
1747
  import { promisify } from "util";
1704
1748
  var exec2 = promisify(execFile);
1705
- var workspace = () => resolve2(process.env.WORKSPACE_DIR ?? join3(process.cwd(), "workspace"));
1706
- var root = () => join3(workspace(), "runtime-inspector");
1707
- var dirs = () => ({ output: join3(root(), "outputs"), state: join3(root(), "state"), tmp: join3(root(), "tmp") });
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") });
1708
1752
  var timestamp = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1709
1753
  var readJson = async (path, fallback) => {
1710
1754
  try {
@@ -1740,26 +1784,26 @@ async function prepare(args) {
1740
1784
  await fs.mkdir(tmp, { recursive: true });
1741
1785
  const batches = [];
1742
1786
  for (let i = 0; i < records.length; i += batchSize) batches.push(records.slice(i, i + batchSize));
1743
- await Promise.all(batches.map((batch, i) => writeJson(join3(tmp, `batch_${String(i).padStart(3, "0")}.json`), batch)));
1744
- 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() });
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() });
1745
1789
  return { status: "batched", totalRecords: records.length, totalBatches: batches.length, tmp };
1746
1790
  }
1747
1791
  async function processBatches() {
1748
1792
  const { tmp, output, state: state2 } = dirs();
1749
- const current = await readJson(join3(state2, "inspect.json"), {});
1793
+ const current = await readJson(join4(state2, "inspect.json"), {});
1750
1794
  if (current.status !== "batched") throw new Error(`runtime state must be batched, got ${String(current.status ?? "missing")}`);
1751
1795
  const names = (await fs.readdir(tmp)).filter((name) => /^batch_\d+\.json$/.test(name)).sort();
1752
1796
  if (!names.length) throw new Error(`no batch files found in ${tmp}`);
1753
1797
  const records = [];
1754
- 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() });
1755
- const path = join3(output, `results_${timestamp()}.json`);
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`);
1756
1800
  await writeJson(path, { total: records.length, processed_at: (/* @__PURE__ */ new Date()).toISOString(), source: current.source, records });
1757
- await writeJson(join3(state2, "inspect.json"), { status: "done", total_processed: records.length, results_path: path, done_at: (/* @__PURE__ */ new Date()).toISOString() });
1801
+ await writeJson(join4(state2, "inspect.json"), { status: "done", total_processed: records.length, results_path: path, done_at: (/* @__PURE__ */ new Date()).toISOString() });
1758
1802
  return { status: "done", total: records.length, resultsPath: path };
1759
1803
  }
1760
1804
  async function state() {
1761
1805
  const { state: stateDir2, output, tmp } = dirs();
1762
- return { state: await readJson(join3(stateDir2, "inspect.json"), null), outputFiles: await fs.readdir(output).catch(() => []), tmpFiles: await fs.readdir(tmp).catch(() => []) };
1806
+ return { state: await readJson(join4(stateDir2, "inspect.json"), null), outputFiles: await fs.readdir(output).catch(() => []), tmpFiles: await fs.readdir(tmp).catch(() => []) };
1763
1807
  }
1764
1808
  async function verify() {
1765
1809
  const snapshot = await state();
@@ -1786,7 +1830,7 @@ async function sandbox(args) {
1786
1830
  }
1787
1831
  async function model(args) {
1788
1832
  if (option(args, "--scenario", true) !== "truncation") throw new Error("only --scenario truncation is supported");
1789
- const target = join3(dirs().tmp, "truncation_test.md");
1833
+ const target = join4(dirs().tmp, "truncation_test.md");
1790
1834
  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." };
1791
1835
  }
1792
1836
  async function runRuntime(action2, args) {
@@ -1799,9 +1843,9 @@ async function runRuntime(action2, args) {
1799
1843
  if (action2 === "write-test") {
1800
1844
  const { output, state: stateDir2 } = dirs();
1801
1845
  const runId = timestamp();
1802
- await writeJson(join3(output, `${runId}_test.json`), { run_id: runId, written_at: (/* @__PURE__ */ new Date()).toISOString() });
1803
- const current = await readJson(join3(stateDir2, "inspect.json"), {});
1804
- await writeJson(join3(stateDir2, "inspect.json"), { ...current, last_run_id: runId, write_count: Number(current.write_count ?? 0) + 1 });
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 });
1805
1849
  return { ok: true, runId };
1806
1850
  }
1807
1851
  throw new Error("runtime action must be prepare, process, state, verify, sandbox, model, or write-test");
@@ -1810,10 +1854,10 @@ async function runRuntime(action2, args) {
1810
1854
  // src/workflows/solvea-kit.ts
1811
1855
  import ExcelJS from "exceljs";
1812
1856
  import { promises as fs2 } from "fs";
1813
- import { dirname as dirname3, join as join4, resolve as resolve3 } from "path";
1814
- var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ?? join4(process.cwd(), "workspace"));
1815
- var outputDir = (owner) => join4(workspace2(), "outputs", owner);
1816
- var stateDir = (owner) => join4(workspace2(), "state", owner);
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);
1817
1861
  var now = () => (/* @__PURE__ */ new Date()).toISOString().replace(/[-:TZ.]/g, "").slice(0, 15);
1818
1862
  var readJson2 = async (path) => JSON.parse(await fs2.readFile(path, "utf8"));
1819
1863
  var writeJson2 = async (path, value) => {
@@ -1843,7 +1887,7 @@ function labelsFrom(value) {
1843
1887
  async function generateLabelImport(args) {
1844
1888
  const input = option(args, "--input") ?? option(args, "--data-file", true);
1845
1889
  const init = args.includes("--init");
1846
- const output = option(args, "--output") ?? join4(stateDir("solvea-kit"), init ? "labels_init.xlsx" : "labels_update.xlsx");
1890
+ const output = option(args, "--output") ?? join5(stateDir("solvea-kit"), init ? "labels_init.xlsx" : "labels_update.xlsx");
1847
1891
  const labels = labelsFrom(await readJson2(input));
1848
1892
  const workbook = new ExcelJS.Workbook();
1849
1893
  const sheet = workbook.addWorksheet("labels");
@@ -1883,9 +1927,9 @@ async function classifyIntents(args) {
1883
1927
  if (!noExcel && !option(args, "--xlsx")) throw new Error("provide --xlsx or --no-excel");
1884
1928
  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 }));
1885
1929
  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: [] };
1886
- const resultPath = join4(outputDir(owner), `results_${runId}.json`);
1930
+ const resultPath = join5(outputDir(owner), `results_${runId}.json`);
1887
1931
  await writeJson2(resultPath, result);
1888
- await writeJson2(join4(stateDir(owner), "progress.json"), { status: "ready", run_id: runId, results_path: resultPath, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1932
+ await writeJson2(join5(stateDir(owner), "progress.json"), { status: "ready", run_id: runId, results_path: resultPath, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
1889
1933
  return { ...result.meta, resultsPath: resultPath };
1890
1934
  }
1891
1935
  async function runSolveaKitWorkflow(action2, args) {
@@ -1895,7 +1939,7 @@ async function runSolveaKitWorkflow(action2, args) {
1895
1939
  }
1896
1940
 
1897
1941
  // src/workflows/support.ts
1898
- import { readFile as readFile4 } from "fs/promises";
1942
+ import { readFile as readFile5 } from "fs/promises";
1899
1943
  import { basename as basename3 } from "path";
1900
1944
  var safe = (value) => encodeURIComponent(value);
1901
1945
  var docsMcpUrl = process.env.CXCLAW_DOCS_MCP_URL ?? "https://solvea-39f11a36.mintlify.app/mcp";
@@ -1970,7 +2014,7 @@ async function runSupport(session, action2, args) {
1970
2014
  const attachments = [];
1971
2015
  for (const file of options2(args, "--attachment")) {
1972
2016
  const form = new FormData();
1973
- form.append("file", new Blob([await readFile4(file)]), basename3(file));
2017
+ form.append("file", new Blob([await readFile5(file)]), basename3(file));
1974
2018
  const tenant = session.tenant;
1975
2019
  const base = tenant?.businessUrl?.replace(/\/$/, "");
1976
2020
  if (!tenant || !base || !tenant.businessToken) throw new Error("no tenant selected");
@@ -2001,24 +2045,24 @@ async function runSupport(session, action2, args) {
2001
2045
  }
2002
2046
 
2003
2047
  // src/workflows/common.ts
2004
- import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
2005
- import { dirname as dirname4, join as join5, resolve as resolve4 } from "path";
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";
2006
2050
  import { homedir as homedir2 } from "os";
2007
- var workspaceRoot = () => resolve4(process.env.CXCLAW_WORKSPACE ?? join5(homedir2(), ".cxclaw", "workspace"));
2008
- var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ?? join5(workspaceRoot(), "state"), domain);
2009
- var outputRoot = (domain) => resolve4(process.env.CXCLAW_OUTPUT_DIR ?? join5(workspaceRoot(), "outputs"), domain);
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);
2010
2054
  async function ensureParent(file) {
2011
- await mkdir3(dirname4(file), { recursive: true });
2055
+ await mkdir4(dirname4(file), { recursive: true });
2012
2056
  }
2013
2057
  async function ensureDir(directory) {
2014
- await mkdir3(directory, { recursive: true });
2058
+ await mkdir4(directory, { recursive: true });
2015
2059
  }
2016
2060
  async function readJson3(file) {
2017
- return JSON.parse(await readFile5(file, "utf8"));
2061
+ return JSON.parse(await readFile6(file, "utf8"));
2018
2062
  }
2019
2063
  async function writeJson3(file, value) {
2020
2064
  await ensureParent(file);
2021
- await writeFile3(file, `${JSON.stringify(value, null, 2)}
2065
+ await writeFile4(file, `${JSON.stringify(value, null, 2)}
2022
2066
  `, "utf8");
2023
2067
  }
2024
2068
  function intOption(args, name, fallback) {
@@ -2036,7 +2080,7 @@ function htmlEscape(value) {
2036
2080
  }
2037
2081
  async function writeHtml(file, title, body) {
2038
2082
  await ensureParent(file);
2039
- 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");
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");
2040
2084
  }
2041
2085
  function asRows(value) {
2042
2086
  if (Array.isArray(value)) return value.filter((item) => item && typeof item === "object");
@@ -2243,13 +2287,13 @@ async function runLocalAgentWorkflow(action2, args) {
2243
2287
  }
2244
2288
  async function writeFileText(file, content) {
2245
2289
  await ensureParent(file);
2246
- const { writeFile: writeFile4 } = await import("fs/promises");
2247
- await writeFile4(file, `${content}
2290
+ const { writeFile: writeFile5 } = await import("fs/promises");
2291
+ await writeFile5(file, `${content}
2248
2292
  `, "utf8");
2249
2293
  }
2250
2294
 
2251
2295
  // src/workflows/tester.ts
2252
- import { join as join6 } from "path";
2296
+ import { join as join7 } from "path";
2253
2297
  import ExcelJS2 from "exceljs";
2254
2298
  async function casesFrom(file) {
2255
2299
  if (file.endsWith(".json")) return asRows(await readJson3(file));
@@ -2271,7 +2315,7 @@ async function casesFrom(file) {
2271
2315
  }
2272
2316
  async function createSheet(args) {
2273
2317
  const cases = option(args, "--cases-file") ? await casesFrom(option(args, "--cases-file")) : [];
2274
- const output = option(args, "--output") ?? join6(outputRoot("agent-tester"), `cases_${Date.now()}.xlsx`);
2318
+ const output = option(args, "--output") ?? join7(outputRoot("agent-tester"), `cases_${Date.now()}.xlsx`);
2275
2319
  await ensureParent(output);
2276
2320
  const workbook = new ExcelJS2.Workbook();
2277
2321
  const sheet = workbook.addWorksheet("cases");
@@ -2297,7 +2341,7 @@ async function runAgentTester(session, action2, args) {
2297
2341
  }
2298
2342
 
2299
2343
  // src/workflows/delivery.ts
2300
- import { join as join7 } from "path";
2344
+ import { join as join8 } from "path";
2301
2345
  import ExcelJS3 from "exceljs";
2302
2346
  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"];
2303
2347
  async function loadRows(file) {
@@ -2331,7 +2375,7 @@ async function writeRows(file, rows) {
2331
2375
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2332
2376
  sheet.addRow(keys);
2333
2377
  rows.forEach((row) => sheet.addRow(keys.map((key) => row[key] ?? "")));
2334
- await ensureDir(join7(file, ".."));
2378
+ await ensureDir(join8(file, ".."));
2335
2379
  await workbook.xlsx.writeFile(file);
2336
2380
  }
2337
2381
  function classify(text) {
@@ -2352,13 +2396,13 @@ async function classifyCases(args, domain) {
2352
2396
  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" }));
2353
2397
  const runId = option(args, "--run-id") ?? Date.now().toString();
2354
2398
  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) };
2355
- const out = option(args, "--results") ?? join7(outputRoot(domain), `results_${runId}.json`);
2399
+ const out = option(args, "--results") ?? join8(outputRoot(domain), `results_${runId}.json`);
2356
2400
  await writeJson3(out, result);
2357
- await writeJson3(join7(stateRoot(domain), "progress.json"), { status: "classified", run_id: runId, results_path: out, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
2401
+ await writeJson3(join8(stateRoot(domain), "progress.json"), { status: "classified", run_id: runId, results_path: out, updated_at: (/* @__PURE__ */ new Date()).toISOString() });
2358
2402
  return { ...result.meta, resultsPath: out };
2359
2403
  }
2360
2404
  async function plan(domain, args) {
2361
- const file = join7(stateRoot(domain), "progress.json");
2405
+ const file = join8(stateRoot(domain), "progress.json");
2362
2406
  let current = {};
2363
2407
  try {
2364
2408
  current = await readJson3(file);
@@ -2382,7 +2426,7 @@ async function plan(domain, args) {
2382
2426
  async function runBatch(client, args, domain) {
2383
2427
  const input = option(args, "--input") ?? option(args, "--test-file", true);
2384
2428
  const rows = await loadRows(input);
2385
- const output = option(args, "--output") ?? join7(outputRoot(domain), `test_results_${Date.now()}.json`);
2429
+ const output = option(args, "--output") ?? join8(outputRoot(domain), `test_results_${Date.now()}.json`);
2386
2430
  const workers = Math.max(1, Math.min(intOption(args, "--workers", 4), 16));
2387
2431
  const results = [];
2388
2432
  let cursor = 0;
@@ -2406,7 +2450,7 @@ async function runBatch(client, args, domain) {
2406
2450
  return { output, total: results.length, succeeded: results.filter((row) => row.ok).length, failed: results.filter((row) => !row.ok).length };
2407
2451
  }
2408
2452
  async function createAgents(client, args, domain) {
2409
- const state2 = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2453
+ const state2 = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2410
2454
  const resultsPath = option(args, "--results") ?? (typeof state2.results_path === "string" ? state2.results_path : void 0);
2411
2455
  if (!resultsPath) throw new Error("classification results are required");
2412
2456
  const result = await readJson3(resultsPath);
@@ -2417,12 +2461,12 @@ async function createAgents(client, args, domain) {
2417
2461
  return { created, count: created.length };
2418
2462
  }
2419
2463
  async function renderReport(args, domain) {
2420
- const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2464
+ const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2421
2465
  const resultsFile = option(args, "--results") ?? option(args, "--input") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2422
2466
  if (!resultsFile) throw new Error("--results/--input is required, or run classify first");
2423
2467
  const value = await readJson3(resultsFile);
2424
2468
  const rows = asRows(value.results ?? value.items ?? value);
2425
- const output = option(args, "--html") ?? option(args, "--output") ?? join7(outputRoot(domain), `${domain}_report.html`);
2469
+ const output = option(args, "--html") ?? option(args, "--output") ?? join8(outputRoot(domain), `${domain}_report.html`);
2426
2470
  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("")}`;
2427
2471
  await writeHtml(output, option(args, "--title") ?? `${domain} report`, body);
2428
2472
  const md = option(args, "--md");
@@ -2433,12 +2477,12 @@ Total: ${rows.length}
2433
2477
  return { output, count: rows.length };
2434
2478
  }
2435
2479
  async function genExcel(args, domain) {
2436
- const progress = await readJson3(join7(stateRoot(domain), "progress.json")).catch(() => ({}));
2480
+ const progress = await readJson3(join8(stateRoot(domain), "progress.json")).catch(() => ({}));
2437
2481
  const input = option(args, "--results") ?? option(args, "--items") ?? (typeof progress.results_path === "string" ? progress.results_path : void 0);
2438
2482
  if (!input) throw new Error("--results or --items is required, or run classify first");
2439
2483
  const value = await readJson3(input);
2440
2484
  const rows = asRows(value);
2441
- const output = option(args, "--output") ?? join7(outputRoot(domain), `${domain}_results.xlsx`);
2485
+ const output = option(args, "--output") ?? join8(outputRoot(domain), `${domain}_results.xlsx`);
2442
2486
  await writeRows(output, rows);
2443
2487
  return { output, count: rows.length };
2444
2488
  }
@@ -2478,7 +2522,7 @@ async function runDomain(session, domain, action2, args) {
2478
2522
  }
2479
2523
 
2480
2524
  // src/workflows/kb-builder.ts
2481
- import { join as join8 } from "path";
2525
+ import { join as join9 } from "path";
2482
2526
  import ExcelJS4 from "exceljs";
2483
2527
  var clean = (value) => String(value ?? "").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
2484
2528
  var absolute = (href, base) => {
@@ -2512,7 +2556,7 @@ async function crawl(args) {
2512
2556
  }
2513
2557
  }
2514
2558
  const result = { url, mode: option(args, "--mode") ?? "auto", pages, fetchedAt: (/* @__PURE__ */ new Date()).toISOString(), total: pages.length };
2515
- const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "crawl_result.json");
2559
+ const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), "crawl_result.json");
2516
2560
  await writeJson3(output, result);
2517
2561
  return { ...result, output };
2518
2562
  }
@@ -2527,13 +2571,13 @@ async function directoryPlan(args) {
2527
2571
  }
2528
2572
  const tree = [...groups.entries()].map(([name, pages]) => ({ name, children: pages.slice(0, 100).map((page2) => ({ name: String(page2.title ?? page2.url), sourceUrl: page2.url })) }));
2529
2573
  const result = { source: option(args, "--crawl-result"), generatedAt: (/* @__PURE__ */ new Date()).toISOString(), tree, confirmed: false };
2530
- const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), "directory_plan.json");
2574
+ const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), "directory_plan.json");
2531
2575
  await writeJson3(output, result);
2532
- if (flag(args, "--write-confirmed-tree")) await writeJson3(join8(stateRoot("kb-builder"), "confirmed_tree.json"), { ...result, confirmed: true });
2576
+ if (flag(args, "--write-confirmed-tree")) await writeJson3(join9(stateRoot("kb-builder"), "confirmed_tree.json"), { ...result, confirmed: true });
2533
2577
  return { output, directories: tree.length, pages: rows.length, tree };
2534
2578
  }
2535
2579
  async function createDirectories(client, args) {
2536
- const file = option(args, "--tree-file") ?? join8(stateRoot("kb-builder"), "confirmed_tree.json");
2580
+ const file = option(args, "--tree-file") ?? join9(stateRoot("kb-builder"), "confirmed_tree.json");
2537
2581
  const value = await readJson3(file);
2538
2582
  const tree = Array.isArray(value.tree) ? value.tree : Array.isArray(value) ? value : [];
2539
2583
  if (!tree.length) throw new Error("confirmed directory tree is empty");
@@ -2556,12 +2600,12 @@ async function createDirectories(client, args) {
2556
2600
  async function extractWebQa(args) {
2557
2601
  const input = await readJson3(option(args, "--crawl-result", true));
2558
2602
  const pages = asRows(input.pages ?? input).slice(0, intOption(args, "--max-pages", 80));
2559
- const outputDir2 = option(args, "--output-dir") ?? join8(outputRoot("kb-builder"), "qa_parts");
2603
+ const outputDir2 = option(args, "--output-dir") ?? join9(outputRoot("kb-builder"), "qa_parts");
2560
2604
  await ensureDir(outputDir2);
2561
2605
  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 }));
2562
2606
  const files = [];
2563
2607
  for (const [index, part] of parts.entries()) {
2564
- const file = join8(outputDir2, `part_${String(index + 1).padStart(4, "0")}.json`);
2608
+ const file = join9(outputDir2, `part_${String(index + 1).padStart(4, "0")}.json`);
2565
2609
  await writeJson3(file, { items: [part] });
2566
2610
  files.push(file);
2567
2611
  }
@@ -2627,9 +2671,9 @@ async function importQa(client, args) {
2627
2671
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2628
2672
  }
2629
2673
  if (fromDir) {
2630
- const { readdir } = await import("fs/promises");
2631
- for (const file of (await readdir(fromDir)).filter((name) => name.endsWith(".json")).sort()) {
2632
- const value = await readJson3(join8(fromDir, file));
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));
2633
2677
  items.push(...Array.isArray(value) ? value : value.items && Array.isArray(value.items) ? value.items : [value]);
2634
2678
  }
2635
2679
  }
@@ -2637,7 +2681,7 @@ async function importQa(client, args) {
2637
2681
  if (!Number.isSafeInteger(maxDepth) || maxDepth <= 0) throw new Error("--max-depth must be a positive integer");
2638
2682
  const normalized = validateQaItems(items, maxDepth);
2639
2683
  const plan2 = { items, count: items.length, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
2640
- const planFile = join8(outputRoot("kb-builder"), `qa_import_plan_${Date.now()}.json`);
2684
+ const planFile = join9(outputRoot("kb-builder"), `qa_import_plan_${Date.now()}.json`);
2641
2685
  await writeJson3(planFile, plan2);
2642
2686
  if (flag(args, "--dry-run")) return { dryRun: true, planFile, count: items.length };
2643
2687
  const directories = flattenDirectories(asRows(await client.listDirectories()));
@@ -2712,7 +2756,7 @@ async function importTemplates(client, args) {
2712
2756
  });
2713
2757
  }
2714
2758
  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);
2715
- const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `template_import_plan_${Date.now()}.json`);
2759
+ const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `template_import_plan_${Date.now()}.json`);
2716
2760
  await writeJson3(output, { items, count: items.length });
2717
2761
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
2718
2762
  const results = [];
@@ -2727,13 +2771,13 @@ async function exportKnowledge(client, args) {
2727
2771
  const value = await client.listKnowledge({ directoryId: id, keyword: option(args, "--keyword") ?? "", type: option(args, "--type") ?? "ALL", pageSize: intOption(args, "--page-size", 1e3) });
2728
2772
  rows.push(...asRows(value).map((row) => ({ ...row, directoryId: id, directoryName: directories.find((dir) => Number(dir.id ?? dir.directoryId) === id)?.name ?? "" })));
2729
2773
  }
2730
- const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `knowledge_${Date.now()}.xlsx`);
2774
+ const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `knowledge_${Date.now()}.xlsx`);
2731
2775
  const workbook = new ExcelJS4.Workbook();
2732
2776
  const sheet = workbook.addWorksheet("knowledge");
2733
2777
  const keys = [...new Set(rows.flatMap((row) => Object.keys(row)))];
2734
2778
  sheet.addRow(keys);
2735
2779
  for (const row of rows) sheet.addRow(keys.map((key) => row[key] ?? ""));
2736
- await ensureDir(join8(output, ".."));
2780
+ await ensureDir(join9(output, ".."));
2737
2781
  await workbook.xlsx.writeFile(output);
2738
2782
  return { output, count: rows.length };
2739
2783
  }
@@ -2774,7 +2818,7 @@ async function extractTicketQa(args) {
2774
2818
  const answer = String(record[replyCol] ?? "").trim();
2775
2819
  if (question && question !== `${brand}:`) items.push({ question, answer, sourceRow: number });
2776
2820
  });
2777
- const output = option(args, "--output") ?? join8(outputRoot("kb-builder"), `ticket_qa_${Date.now()}.json`);
2821
+ const output = option(args, "--output") ?? join9(outputRoot("kb-builder"), `ticket_qa_${Date.now()}.json`);
2778
2822
  const result = { brand, count: items.length, items };
2779
2823
  await writeJson3(output, result);
2780
2824
  if (flag(args, "--dry-run")) return { dryRun: true, output, count: items.length };
@@ -2782,12 +2826,12 @@ async function extractTicketQa(args) {
2782
2826
  }
2783
2827
 
2784
2828
  // src/workflows/desk.ts
2785
- import { join as join9 } from "path";
2829
+ import { join as join10 } from "path";
2786
2830
  import ExcelJS5 from "exceljs";
2787
2831
  var taskId = (args) => option(args, "--task-id") ?? (/* @__PURE__ */ new Date()).toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
2788
- var taskDir = (args) => join9(stateRoot("solvea-desk"), taskId(args));
2832
+ var taskDir = (args) => join10(stateRoot("solvea-desk"), taskId(args));
2789
2833
  async function saveDatasource(dir, name, rows) {
2790
- const file = join9(dir, name);
2834
+ const file = join10(dir, name);
2791
2835
  await ensureParent(file);
2792
2836
  const workbook = new ExcelJS5.Workbook();
2793
2837
  const sheet = workbook.addWorksheet("data");
@@ -2810,7 +2854,7 @@ async function fetchTickets(client, args) {
2810
2854
  if (pageRows.length < pageSize2) break;
2811
2855
  }
2812
2856
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2813
- await writeJson3(join9(dir, "metadata.json"), { taskId: taskId(args), rows: rows.length, output });
2857
+ await writeJson3(join10(dir, "metadata.json"), { taskId: taskId(args), rows: rows.length, output });
2814
2858
  return { taskId: taskId(args), output, count: rows.length };
2815
2859
  }
2816
2860
  async function fetchSources(client, args) {
@@ -2821,7 +2865,7 @@ async function fetchSources(client, args) {
2821
2865
  const rows = asRows(value).slice(0, intOption(args, "--max-rows", 1e4));
2822
2866
  sources.tickets = rows;
2823
2867
  const output = await saveDatasource(dir, "datasource.xlsx", rows);
2824
- await writeJson3(join9(dir, "sources.json"), sources);
2868
+ await writeJson3(join10(dir, "sources.json"), sources);
2825
2869
  return { taskId: taskId(args), output, count: rows.length };
2826
2870
  }
2827
2871
  async function tags(client, action2, args) {
@@ -2848,10 +2892,10 @@ async function tags(client, action2, args) {
2848
2892
  throw new Error(`unknown tag action: ${action2}`);
2849
2893
  }
2850
2894
  async function renderReport2(args) {
2851
- const dir = taskDir(args), dataFile = option(args, "--report-data") ?? join9(dir, "report_data.json"), notesFile = option(args, "--notes") ?? join9(dir, "calculation_notes.json");
2895
+ const dir = taskDir(args), dataFile = option(args, "--report-data") ?? join10(dir, "report_data.json"), notesFile = option(args, "--notes") ?? join10(dir, "calculation_notes.json");
2852
2896
  const data3 = await readJson3(dataFile);
2853
2897
  if (flag(args, "--validate-only")) return { valid: true, dataFile };
2854
- const output = option(args, "--output") ?? join9(outputRoot("solvea-desk"), taskId(args), `${option(args, "--report-slug") ?? "report"}.html`);
2898
+ const output = option(args, "--output") ?? join10(outputRoot("solvea-desk"), taskId(args), `${option(args, "--report-slug") ?? "report"}.html`);
2855
2899
  const body = `<pre>${htmlEscape(JSON.stringify({ data: data3, notes: await readJson3(notesFile).catch(() => ({})) }, null, 2))}</pre>`;
2856
2900
  await writeHtml(output, option(args, "--report-slug") ?? "Solvea Desk report", body);
2857
2901
  return { output, valid: true };
@@ -2971,7 +3015,7 @@ async function main(args = process.argv.slice(2)) {
2971
3015
  if (flag(args, "--scheduled")) await new Promise((resolve5) => setTimeout(resolve5, Math.random() * 18e5));
2972
3016
  return print(await update());
2973
3017
  }
2974
- if (command === "commands" || command === "capabilities") console.log(await readFile6(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
3018
+ if (command === "commands" || command === "capabilities") console.log(await readFile7(new URL("../capabilities.lock.json", import.meta.url), "utf8"));
2975
3019
  else throw new Error(`unknown command: ${command}`);
2976
3020
  }
2977
3021
  main().catch((error) => {