@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/README.md +2 -2
- package/capabilities.lock.json +3 -3
- package/dist/cli.js +139 -139
- package/dist/cli.js.map +1 -1
- package/package.json +1 -2
- package/runtime/auth-wait-state.d.mts +0 -6
- package/runtime/auth-wait-state.mjs +0 -56
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
|
|
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.
|
|
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
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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\
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
305
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
306
306
|
|
|
307
307
|
// src/solvea/client.ts
|
|
308
|
-
import { mkdir
|
|
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
|
|
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
|
|
774
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
1616
|
+
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
1617
1617
|
import { homedir, platform } from "os";
|
|
1618
|
-
import { isAbsolute, join as
|
|
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 =
|
|
1692
|
-
const path =
|
|
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
|
|
1695
|
-
await
|
|
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 =
|
|
1707
|
+
const dir = join2(homedir(), ".config/systemd/user");
|
|
1708
1708
|
const command = [invocation.command, ...invocation.args].map(systemdArg).join(" ");
|
|
1709
|
-
await
|
|
1710
|
-
await
|
|
1711
|
-
|
|
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
|
|
1718
|
-
|
|
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
|
|
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 ??
|
|
1761
|
-
var root = () =>
|
|
1762
|
-
var dirs = () => ({ output:
|
|
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(
|
|
1799
|
-
await writeJson(
|
|
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(
|
|
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(
|
|
1810
|
-
const path =
|
|
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(
|
|
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(
|
|
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 =
|
|
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(
|
|
1858
|
-
const current = await readJson(
|
|
1859
|
-
await writeJson(
|
|
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
|
|
1869
|
-
var workspace2 = () => resolve3(process.env.WORKSPACE_DIR ??
|
|
1870
|
-
var outputDir = (owner) =>
|
|
1871
|
-
var stateDir = (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") ??
|
|
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 =
|
|
1941
|
+
const resultPath = join4(outputDir(owner), `results_${runId}.json`);
|
|
1942
1942
|
await writeJson2(resultPath, result);
|
|
1943
|
-
await writeJson2(
|
|
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
|
|
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
|
|
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
|
|
2060
|
-
import { dirname as dirname4, join as
|
|
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 ??
|
|
2063
|
-
var stateRoot = (domain) => resolve4(process.env.CXCLAW_STATE_DIR ??
|
|
2064
|
-
var outputRoot = (domain) => resolve4(process.env.CXCLAW_OUTPUT_DIR ??
|
|
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
|
|
2066
|
+
await mkdir3(dirname4(file), { recursive: true });
|
|
2067
2067
|
}
|
|
2068
2068
|
async function ensureDir(directory) {
|
|
2069
|
-
await
|
|
2069
|
+
await mkdir3(directory, { recursive: true });
|
|
2070
2070
|
}
|
|
2071
2071
|
async function readJson3(file) {
|
|
2072
|
-
return JSON.parse(await
|
|
2072
|
+
return JSON.parse(await readFile5(file, "utf8"));
|
|
2073
2073
|
}
|
|
2074
2074
|
async function writeJson3(file, value) {
|
|
2075
2075
|
await ensureParent(file);
|
|
2076
|
-
await
|
|
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
|
|
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:
|
|
2302
|
-
await
|
|
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
|
|
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") ??
|
|
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
|
|
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(
|
|
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") ??
|
|
2410
|
+
const out = option(args, "--results") ?? join7(outputRoot(domain), `results_${runId}.json`);
|
|
2411
2411
|
await writeJson3(out, result);
|
|
2412
|
-
await writeJson3(
|
|
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 =
|
|
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") ??
|
|
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(
|
|
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(
|
|
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") ??
|
|
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(
|
|
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") ??
|
|
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
|
|
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") ??
|
|
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") ??
|
|
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(
|
|
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") ??
|
|
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") ??
|
|
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 =
|
|
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
|
|
2686
|
-
for (const file of (await
|
|
2687
|
-
const value = await readJson3(
|
|
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 =
|
|
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") ??
|
|
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") ??
|
|
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(
|
|
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") ??
|
|
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
|
|
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) =>
|
|
2843
|
+
var taskDir = (args) => join9(stateRoot("solvea-desk"), taskId(args));
|
|
2844
2844
|
async function saveDatasource(dir, name, rows) {
|
|
2845
|
-
const file =
|
|
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(
|
|
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(
|
|
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") ??
|
|
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") ??
|
|
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,
|
|
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
|
|
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
|
-
|
|
3034
|
-
|
|
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
|