@puyinkai/xiaobao-cli 0.1.0
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 +81 -0
- package/dist/api-Ccj5dLMo.mjs +100 -0
- package/dist/api-client-DwySN6x-.mjs +75 -0
- package/dist/audio-VmDQMq59.mjs +14 -0
- package/dist/auth-ChHvqjCS.mjs +15 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +30 -0
- package/dist/consultant-ABFTL_jx.mjs +11 -0
- package/dist/customer-DtSnQqy_.mjs +11 -0
- package/dist/device-flow-BgsZipYA.mjs +166 -0
- package/dist/focus-BDYuP2vZ.mjs +11 -0
- package/dist/format-BZvv8lYc.mjs +610 -0
- package/dist/headers-D79npewp.mjs +11 -0
- package/dist/list--o5Q_PI8.mjs +80 -0
- package/dist/list-Bkyi95YO.mjs +76 -0
- package/dist/list-CGACp0y-.mjs +76 -0
- package/dist/list-CVKSGNu4.mjs +91 -0
- package/dist/list-CzB9_Jho.mjs +91 -0
- package/dist/list-DW6KAAaC.mjs +92 -0
- package/dist/list-iwd9cH1I.mjs +41 -0
- package/dist/login-BwkrByMm.mjs +91 -0
- package/dist/logout-BJm9pjje.mjs +49 -0
- package/dist/project-Ba05YzJ5.mjs +14 -0
- package/dist/project-store-Bz5kf-EI.mjs +62 -0
- package/dist/qa-D-B9FV9W.mjs +60 -0
- package/dist/resistance-Cf7zsdB3.mjs +11 -0
- package/dist/text-BLH4R3xv.mjs +49 -0
- package/dist/token-store-CHZ_rJQk.mjs +85 -0
- package/dist/use-DV9Ii3Tn.mjs +61 -0
- package/dist/util-DgwkUfV9.mjs +46 -0
- package/dist/visit-Ct3Vea8I.mjs +11 -0
- package/dist/whoami-DwTHvI4B.mjs +51 -0
- package/package.json +36 -0
- package/skills/wangxiaobao-audio-query/SKILL.md +252 -0
- package/skills/wangxiaobao-audio-wiki/SKILL.md +332 -0
- package/skills/wangxiaobao-customer-focus-query/SKILL.md +213 -0
- package/skills/wangxiaobao-customer-query/SKILL.md +214 -0
- package/skills/wangxiaobao-customer-resistance-query/SKILL.md +211 -0
- package/skills/wangxiaobao-quick-qa/SKILL.md +238 -0
- package/skills/wangxiaobao-switch-project/SKILL.md +179 -0
- package/skills/wangxiaobao-visit-query/SKILL.md +249 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
//#region node_modules/.pnpm/@toon-format+toon@2.2.0/node_modules/@toon-format/toon/dist/index.mjs
|
|
2
|
+
const NULL_LITERAL = "null";
|
|
3
|
+
const DEFAULT_DELIMITER = {
|
|
4
|
+
comma: ",",
|
|
5
|
+
tab: " ",
|
|
6
|
+
pipe: "|"
|
|
7
|
+
}.comma;
|
|
8
|
+
/**
|
|
9
|
+
* Escapes special characters in a string for encoding.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* Handles backslashes, quotes, newlines, carriage returns, and tabs.
|
|
13
|
+
*/
|
|
14
|
+
function escapeString(value) {
|
|
15
|
+
return value.replace(/\\/g, `\\\\`).replace(/"/g, `\\"`).replace(/\n/g, `\\n`).replace(/\r/g, `\\r`).replace(/\t/g, `\\t`);
|
|
16
|
+
}
|
|
17
|
+
function isBooleanOrNullLiteral(token) {
|
|
18
|
+
return token === "true" || token === "false" || token === "null";
|
|
19
|
+
}
|
|
20
|
+
function normalizeValue(value) {
|
|
21
|
+
if (value === null) return null;
|
|
22
|
+
if (typeof value === "object" && value !== null && "toJSON" in value && typeof value.toJSON === "function") {
|
|
23
|
+
const next = value.toJSON();
|
|
24
|
+
if (next !== value) return normalizeValue(next);
|
|
25
|
+
}
|
|
26
|
+
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
27
|
+
if (typeof value === "number") {
|
|
28
|
+
if (Object.is(value, -0)) return 0;
|
|
29
|
+
if (!Number.isFinite(value)) return null;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === "bigint") {
|
|
33
|
+
if (value >= Number.MIN_SAFE_INTEGER && value <= Number.MAX_SAFE_INTEGER) return Number(value);
|
|
34
|
+
return value.toString();
|
|
35
|
+
}
|
|
36
|
+
if (value instanceof Date) return value.toISOString();
|
|
37
|
+
if (Array.isArray(value)) return value.map(normalizeValue);
|
|
38
|
+
if (value instanceof Set) return Array.from(value).map(normalizeValue);
|
|
39
|
+
if (value instanceof Map) return Object.fromEntries(Array.from(value, ([k, v]) => [String(k), normalizeValue(v)]));
|
|
40
|
+
if (isPlainObject(value)) {
|
|
41
|
+
const encodedValues = {};
|
|
42
|
+
for (const key in value) if (Object.hasOwn(value, key)) encodedValues[key] = normalizeValue(value[key]);
|
|
43
|
+
return encodedValues;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
function isJsonPrimitive(value) {
|
|
48
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
49
|
+
}
|
|
50
|
+
function isJsonArray(value) {
|
|
51
|
+
return Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
function isJsonObject(value) {
|
|
54
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
55
|
+
}
|
|
56
|
+
function isEmptyObject(value) {
|
|
57
|
+
return Object.keys(value).length === 0;
|
|
58
|
+
}
|
|
59
|
+
function isPlainObject(value) {
|
|
60
|
+
if (value === null || typeof value !== "object") return false;
|
|
61
|
+
const prototype = Object.getPrototypeOf(value);
|
|
62
|
+
return prototype === null || prototype === Object.prototype;
|
|
63
|
+
}
|
|
64
|
+
function isArrayOfPrimitives(value) {
|
|
65
|
+
return value.length === 0 || value.every((item) => isJsonPrimitive(item));
|
|
66
|
+
}
|
|
67
|
+
function isArrayOfArrays(value) {
|
|
68
|
+
return value.length === 0 || value.every((item) => isJsonArray(item));
|
|
69
|
+
}
|
|
70
|
+
function isArrayOfObjects(value) {
|
|
71
|
+
return value.length === 0 || value.every((item) => isJsonObject(item));
|
|
72
|
+
}
|
|
73
|
+
const NUMERIC_LIKE_PATTERN = /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
|
|
74
|
+
const LEADING_ZERO_PATTERN = /^0\d+$/;
|
|
75
|
+
/**
|
|
76
|
+
* Checks if a key can be used without quotes.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* Valid unquoted keys must start with a letter or underscore,
|
|
80
|
+
* followed by letters, digits, underscores, or dots.
|
|
81
|
+
*/
|
|
82
|
+
function isValidUnquotedKey(key) {
|
|
83
|
+
return /^[A-Z_][\w.]*$/i.test(key);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Checks if a key segment is a valid identifier for safe folding/expansion.
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* Identifier segments are more restrictive than unquoted keys:
|
|
90
|
+
* - Must start with a letter or underscore
|
|
91
|
+
* - Followed only by letters, digits, or underscores (no dots)
|
|
92
|
+
* - Used for safe key folding and path expansion
|
|
93
|
+
*/
|
|
94
|
+
function isIdentifierSegment(key) {
|
|
95
|
+
return /^[A-Z_]\w*$/i.test(key);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Determines if a string value can be safely encoded without quotes.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* A string needs quoting if it:
|
|
102
|
+
* - Is empty
|
|
103
|
+
* - Has leading or trailing whitespace
|
|
104
|
+
* - Could be confused with a literal (boolean, null, number)
|
|
105
|
+
* - Contains structural characters (colons, brackets, braces)
|
|
106
|
+
* - Contains quotes or backslashes (need escaping)
|
|
107
|
+
* - Contains control characters (newlines, tabs, etc.)
|
|
108
|
+
* - Contains the active delimiter
|
|
109
|
+
* - Starts with a list marker (hyphen)
|
|
110
|
+
*/
|
|
111
|
+
function isSafeUnquoted(value, delimiter = DEFAULT_DELIMITER) {
|
|
112
|
+
if (!value) return false;
|
|
113
|
+
if (value !== value.trim()) return false;
|
|
114
|
+
if (isBooleanOrNullLiteral(value) || isNumericLike(value)) return false;
|
|
115
|
+
if (value.includes(":")) return false;
|
|
116
|
+
if (value.includes("\"") || value.includes("\\")) return false;
|
|
117
|
+
if (/[[\]{}]/.test(value)) return false;
|
|
118
|
+
if (/[\n\r\t]/.test(value)) return false;
|
|
119
|
+
if (value.includes(delimiter)) return false;
|
|
120
|
+
if (value.startsWith("-")) return false;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Checks if a string looks like a number.
|
|
125
|
+
*
|
|
126
|
+
* @remarks
|
|
127
|
+
* Match numbers like `42`, `-3.14`, `1e-6`, `05`, etc.
|
|
128
|
+
*/
|
|
129
|
+
function isNumericLike(value) {
|
|
130
|
+
return NUMERIC_LIKE_PATTERN.test(value) || LEADING_ZERO_PATTERN.test(value);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Attempts to fold a single-key object chain into a dotted path.
|
|
134
|
+
*
|
|
135
|
+
* @remarks
|
|
136
|
+
* Folding traverses nested objects with single keys, collapsing them into a dotted path.
|
|
137
|
+
* It stops when:
|
|
138
|
+
* - A non-single-key object is encountered
|
|
139
|
+
* - An array is encountered (arrays are not "single-key objects")
|
|
140
|
+
* - A primitive value is reached
|
|
141
|
+
* - The flatten depth limit is reached
|
|
142
|
+
* - Any segment fails safe mode validation
|
|
143
|
+
*
|
|
144
|
+
* Safe mode requirements:
|
|
145
|
+
* - `options.keyFolding` must be `'safe'`
|
|
146
|
+
* - Every segment must be a valid identifier (no dots, no special chars)
|
|
147
|
+
* - The folded key must not collide with existing sibling keys
|
|
148
|
+
* - No segment should require quoting
|
|
149
|
+
*
|
|
150
|
+
* @param key - The starting key to fold
|
|
151
|
+
* @param value - The value associated with the key
|
|
152
|
+
* @param siblings - Array of all sibling keys at this level (for collision detection)
|
|
153
|
+
* @param options - Resolved encoding options
|
|
154
|
+
* @returns A FoldResult if folding is possible, undefined otherwise
|
|
155
|
+
*/
|
|
156
|
+
function tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, flattenDepth) {
|
|
157
|
+
if (options.keyFolding !== "safe") return;
|
|
158
|
+
if (!isJsonObject(value)) return;
|
|
159
|
+
const { segments, tail, leafValue } = collectSingleKeyChain(key, value, flattenDepth ?? options.flattenDepth);
|
|
160
|
+
if (segments.length < 2) return;
|
|
161
|
+
if (!segments.every((seg) => isIdentifierSegment(seg))) return;
|
|
162
|
+
const foldedKey = buildFoldedKey(segments);
|
|
163
|
+
const absolutePath = pathPrefix ? `${pathPrefix}.${foldedKey}` : foldedKey;
|
|
164
|
+
if (siblings.includes(foldedKey)) return;
|
|
165
|
+
if (rootLiteralKeys && rootLiteralKeys.has(absolutePath)) return;
|
|
166
|
+
return {
|
|
167
|
+
foldedKey,
|
|
168
|
+
remainder: tail,
|
|
169
|
+
leafValue,
|
|
170
|
+
segmentCount: segments.length
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Collects a chain of single-key objects into segments.
|
|
175
|
+
*
|
|
176
|
+
* @remarks
|
|
177
|
+
* Traverses nested objects, collecting keys until:
|
|
178
|
+
* - A non-single-key object is found
|
|
179
|
+
* - An array is encountered
|
|
180
|
+
* - A primitive is reached
|
|
181
|
+
* - An empty object is reached
|
|
182
|
+
* - The depth limit is reached
|
|
183
|
+
*
|
|
184
|
+
* @param startKey - The initial key to start the chain
|
|
185
|
+
* @param startValue - The value to traverse
|
|
186
|
+
* @param maxDepth - Maximum number of segments to collect
|
|
187
|
+
* @returns Object containing segments array, tail value, and leaf value
|
|
188
|
+
*/
|
|
189
|
+
function collectSingleKeyChain(startKey, startValue, maxDepth) {
|
|
190
|
+
const segments = [startKey];
|
|
191
|
+
let currentValue = startValue;
|
|
192
|
+
while (segments.length < maxDepth) {
|
|
193
|
+
if (!isJsonObject(currentValue)) break;
|
|
194
|
+
const keys = Object.keys(currentValue);
|
|
195
|
+
if (keys.length !== 1) break;
|
|
196
|
+
const nextKey = keys[0];
|
|
197
|
+
const nextValue = currentValue[nextKey];
|
|
198
|
+
segments.push(nextKey);
|
|
199
|
+
currentValue = nextValue;
|
|
200
|
+
}
|
|
201
|
+
if (!isJsonObject(currentValue) || isEmptyObject(currentValue)) return {
|
|
202
|
+
segments,
|
|
203
|
+
tail: void 0,
|
|
204
|
+
leafValue: currentValue
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
segments,
|
|
208
|
+
tail: currentValue,
|
|
209
|
+
leafValue: currentValue
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function buildFoldedKey(segments) {
|
|
213
|
+
return segments.join(".");
|
|
214
|
+
}
|
|
215
|
+
function encodePrimitive(value, delimiter) {
|
|
216
|
+
if (value === null) return NULL_LITERAL;
|
|
217
|
+
if (typeof value === "boolean") return String(value);
|
|
218
|
+
if (typeof value === "number") return String(value);
|
|
219
|
+
return encodeStringLiteral(value, delimiter);
|
|
220
|
+
}
|
|
221
|
+
function encodeStringLiteral(value, delimiter = DEFAULT_DELIMITER) {
|
|
222
|
+
if (isSafeUnquoted(value, delimiter)) return value;
|
|
223
|
+
return `"${escapeString(value)}"`;
|
|
224
|
+
}
|
|
225
|
+
function encodeKey(key) {
|
|
226
|
+
if (isValidUnquotedKey(key)) return key;
|
|
227
|
+
return `"${escapeString(key)}"`;
|
|
228
|
+
}
|
|
229
|
+
function encodeAndJoinPrimitives(values, delimiter = DEFAULT_DELIMITER) {
|
|
230
|
+
return values.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
231
|
+
}
|
|
232
|
+
function formatHeader(length, options) {
|
|
233
|
+
const key = options?.key;
|
|
234
|
+
const fields = options?.fields;
|
|
235
|
+
const delimiter = options?.delimiter ?? ",";
|
|
236
|
+
let header = "";
|
|
237
|
+
if (key != null) header += encodeKey(key);
|
|
238
|
+
header += `[${length}${delimiter !== DEFAULT_DELIMITER ? delimiter : ""}]`;
|
|
239
|
+
if (fields) {
|
|
240
|
+
const quotedFields = fields.map((f) => encodeKey(f));
|
|
241
|
+
header += `{${quotedFields.join(delimiter)}}`;
|
|
242
|
+
}
|
|
243
|
+
header += ":";
|
|
244
|
+
return header;
|
|
245
|
+
}
|
|
246
|
+
function* encodeJsonValue(value, options, depth) {
|
|
247
|
+
if (isJsonPrimitive(value)) {
|
|
248
|
+
const encodedPrimitive = encodePrimitive(value, options.delimiter);
|
|
249
|
+
if (encodedPrimitive !== "") yield encodedPrimitive;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (isJsonArray(value)) yield* encodeArrayLines(void 0, value, depth, options);
|
|
253
|
+
else if (isJsonObject(value)) yield* encodeObjectLines(value, depth, options);
|
|
254
|
+
}
|
|
255
|
+
function* encodeObjectLines(value, depth, options, rootLiteralKeys, pathPrefix, remainingDepth) {
|
|
256
|
+
const keys = Object.keys(value);
|
|
257
|
+
if (depth === 0 && !rootLiteralKeys) rootLiteralKeys = new Set(keys.filter((k) => k.includes(".")));
|
|
258
|
+
const effectiveFlattenDepth = remainingDepth ?? options.flattenDepth;
|
|
259
|
+
for (const [key, val] of Object.entries(value)) yield* encodeKeyValuePairLines(key, val, depth, options, keys, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
|
|
260
|
+
}
|
|
261
|
+
function* encodeKeyValuePairLines(key, value, depth, options, siblings, rootLiteralKeys, pathPrefix, flattenDepth) {
|
|
262
|
+
const currentPath = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
263
|
+
const effectiveFlattenDepth = flattenDepth ?? options.flattenDepth;
|
|
264
|
+
if (options.keyFolding === "safe" && siblings) {
|
|
265
|
+
const foldResult = tryFoldKeyChain(key, value, siblings, options, rootLiteralKeys, pathPrefix, effectiveFlattenDepth);
|
|
266
|
+
if (foldResult) {
|
|
267
|
+
const { foldedKey, remainder, leafValue, segmentCount } = foldResult;
|
|
268
|
+
const encodedFoldedKey = encodeKey(foldedKey);
|
|
269
|
+
if (remainder === void 0) {
|
|
270
|
+
if (isJsonPrimitive(leafValue)) {
|
|
271
|
+
yield indentedLine(depth, `${encodedFoldedKey}: ${encodePrimitive(leafValue, options.delimiter)}`, options.indent);
|
|
272
|
+
return;
|
|
273
|
+
} else if (isJsonArray(leafValue)) {
|
|
274
|
+
yield* encodeArrayLines(foldedKey, leafValue, depth, options);
|
|
275
|
+
return;
|
|
276
|
+
} else if (isJsonObject(leafValue) && isEmptyObject(leafValue)) {
|
|
277
|
+
yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (isJsonObject(remainder)) {
|
|
282
|
+
yield indentedLine(depth, `${encodedFoldedKey}:`, options.indent);
|
|
283
|
+
const remainingDepth = effectiveFlattenDepth - segmentCount;
|
|
284
|
+
const foldedPath = pathPrefix ? `${pathPrefix}.${foldedKey}` : foldedKey;
|
|
285
|
+
yield* encodeObjectLines(remainder, depth + 1, options, rootLiteralKeys, foldedPath, remainingDepth);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const encodedKey = encodeKey(key);
|
|
291
|
+
if (isJsonPrimitive(value)) yield indentedLine(depth, `${encodedKey}: ${encodePrimitive(value, options.delimiter)}`, options.indent);
|
|
292
|
+
else if (isJsonArray(value)) yield* encodeArrayLines(key, value, depth, options);
|
|
293
|
+
else if (isJsonObject(value)) {
|
|
294
|
+
yield indentedLine(depth, `${encodedKey}:`, options.indent);
|
|
295
|
+
if (!isEmptyObject(value)) yield* encodeObjectLines(value, depth + 1, options, rootLiteralKeys, currentPath, effectiveFlattenDepth);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function* encodeArrayLines(key, value, depth, options) {
|
|
299
|
+
if (value.length === 0) {
|
|
300
|
+
yield indentedLine(depth, formatHeader(0, {
|
|
301
|
+
key,
|
|
302
|
+
delimiter: options.delimiter
|
|
303
|
+
}), options.indent);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (isArrayOfPrimitives(value)) {
|
|
307
|
+
yield indentedLine(depth, encodeInlineArrayLine(value, options.delimiter, key), options.indent);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (isArrayOfArrays(value)) {
|
|
311
|
+
if (value.every((arr) => isArrayOfPrimitives(arr))) {
|
|
312
|
+
yield* encodeArrayOfArraysAsListItemsLines(key, value, depth, options);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (isArrayOfObjects(value)) {
|
|
317
|
+
const header = extractTabularHeader(value);
|
|
318
|
+
if (header) yield* encodeArrayOfObjectsAsTabularLines(key, value, header, depth, options);
|
|
319
|
+
else yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
yield* encodeMixedArrayAsListItemsLines(key, value, depth, options);
|
|
323
|
+
}
|
|
324
|
+
function* encodeArrayOfArraysAsListItemsLines(prefix, values, depth, options) {
|
|
325
|
+
yield indentedLine(depth, formatHeader(values.length, {
|
|
326
|
+
key: prefix,
|
|
327
|
+
delimiter: options.delimiter
|
|
328
|
+
}), options.indent);
|
|
329
|
+
for (const arr of values) if (isArrayOfPrimitives(arr)) {
|
|
330
|
+
const arrayLine = encodeInlineArrayLine(arr, options.delimiter);
|
|
331
|
+
yield indentedListItem(depth + 1, arrayLine, options.indent);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
function encodeInlineArrayLine(values, delimiter, prefix) {
|
|
335
|
+
const header = formatHeader(values.length, {
|
|
336
|
+
key: prefix,
|
|
337
|
+
delimiter
|
|
338
|
+
});
|
|
339
|
+
const joinedValue = encodeAndJoinPrimitives(values, delimiter);
|
|
340
|
+
if (values.length === 0) return header;
|
|
341
|
+
return `${header} ${joinedValue}`;
|
|
342
|
+
}
|
|
343
|
+
function* encodeArrayOfObjectsAsTabularLines(prefix, rows, header, depth, options) {
|
|
344
|
+
yield indentedLine(depth, formatHeader(rows.length, {
|
|
345
|
+
key: prefix,
|
|
346
|
+
fields: header,
|
|
347
|
+
delimiter: options.delimiter
|
|
348
|
+
}), options.indent);
|
|
349
|
+
yield* writeTabularRowsLines(rows, header, depth + 1, options);
|
|
350
|
+
}
|
|
351
|
+
function extractTabularHeader(rows) {
|
|
352
|
+
if (rows.length === 0) return;
|
|
353
|
+
const firstRow = rows[0];
|
|
354
|
+
const firstKeys = Object.keys(firstRow);
|
|
355
|
+
if (firstKeys.length === 0) return;
|
|
356
|
+
if (isTabularArray(rows, firstKeys)) return firstKeys;
|
|
357
|
+
}
|
|
358
|
+
function isTabularArray(rows, header) {
|
|
359
|
+
for (const row of rows) {
|
|
360
|
+
if (Object.keys(row).length !== header.length) return false;
|
|
361
|
+
for (const key of header) {
|
|
362
|
+
if (!(key in row)) return false;
|
|
363
|
+
if (!isJsonPrimitive(row[key])) return false;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
function* writeTabularRowsLines(rows, header, depth, options) {
|
|
369
|
+
for (const row of rows) yield indentedLine(depth, encodeAndJoinPrimitives(header.map((key) => row[key]), options.delimiter), options.indent);
|
|
370
|
+
}
|
|
371
|
+
function* encodeMixedArrayAsListItemsLines(prefix, items, depth, options) {
|
|
372
|
+
yield indentedLine(depth, formatHeader(items.length, {
|
|
373
|
+
key: prefix,
|
|
374
|
+
delimiter: options.delimiter
|
|
375
|
+
}), options.indent);
|
|
376
|
+
for (const item of items) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
377
|
+
}
|
|
378
|
+
function* encodeObjectAsListItemLines(obj, depth, options) {
|
|
379
|
+
if (isEmptyObject(obj)) {
|
|
380
|
+
yield indentedLine(depth, "-", options.indent);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const entries = Object.entries(obj);
|
|
384
|
+
const [firstKey, firstValue] = entries[0];
|
|
385
|
+
const restEntries = entries.slice(1);
|
|
386
|
+
if (isJsonArray(firstValue) && isArrayOfObjects(firstValue)) {
|
|
387
|
+
const header = extractTabularHeader(firstValue);
|
|
388
|
+
if (header) {
|
|
389
|
+
yield indentedListItem(depth, formatHeader(firstValue.length, {
|
|
390
|
+
key: firstKey,
|
|
391
|
+
fields: header,
|
|
392
|
+
delimiter: options.delimiter
|
|
393
|
+
}), options.indent);
|
|
394
|
+
yield* writeTabularRowsLines(firstValue, header, depth + 2, options);
|
|
395
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
const encodedKey = encodeKey(firstKey);
|
|
400
|
+
if (isJsonPrimitive(firstValue)) yield indentedListItem(depth, `${encodedKey}: ${encodePrimitive(firstValue, options.delimiter)}`, options.indent);
|
|
401
|
+
else if (isJsonArray(firstValue)) if (firstValue.length === 0) yield indentedListItem(depth, `${encodedKey}${formatHeader(0, { delimiter: options.delimiter })}`, options.indent);
|
|
402
|
+
else if (isArrayOfPrimitives(firstValue)) yield indentedListItem(depth, `${encodedKey}${encodeInlineArrayLine(firstValue, options.delimiter)}`, options.indent);
|
|
403
|
+
else {
|
|
404
|
+
yield indentedListItem(depth, `${encodedKey}${formatHeader(firstValue.length, { delimiter: options.delimiter })}`, options.indent);
|
|
405
|
+
for (const item of firstValue) yield* encodeListItemValueLines(item, depth + 2, options);
|
|
406
|
+
}
|
|
407
|
+
else if (isJsonObject(firstValue)) {
|
|
408
|
+
yield indentedListItem(depth, `${encodedKey}:`, options.indent);
|
|
409
|
+
if (!isEmptyObject(firstValue)) yield* encodeObjectLines(firstValue, depth + 2, options);
|
|
410
|
+
}
|
|
411
|
+
if (restEntries.length > 0) yield* encodeObjectLines(Object.fromEntries(restEntries), depth + 1, options);
|
|
412
|
+
}
|
|
413
|
+
function* encodeListItemValueLines(value, depth, options) {
|
|
414
|
+
if (isJsonPrimitive(value)) yield indentedListItem(depth, encodePrimitive(value, options.delimiter), options.indent);
|
|
415
|
+
else if (isJsonArray(value)) if (isArrayOfPrimitives(value)) yield indentedListItem(depth, encodeInlineArrayLine(value, options.delimiter), options.indent);
|
|
416
|
+
else {
|
|
417
|
+
yield indentedListItem(depth, formatHeader(value.length, { delimiter: options.delimiter }), options.indent);
|
|
418
|
+
for (const item of value) yield* encodeListItemValueLines(item, depth + 1, options);
|
|
419
|
+
}
|
|
420
|
+
else if (isJsonObject(value)) yield* encodeObjectAsListItemLines(value, depth, options);
|
|
421
|
+
}
|
|
422
|
+
function indentedLine(depth, content, indentSize) {
|
|
423
|
+
return " ".repeat(indentSize * depth) + content;
|
|
424
|
+
}
|
|
425
|
+
function indentedListItem(depth, content, indentSize) {
|
|
426
|
+
return indentedLine(depth, "- " + content, indentSize);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Applies a replacer function to a `JsonValue` and all its descendants.
|
|
430
|
+
*
|
|
431
|
+
* The replacer is called for:
|
|
432
|
+
* - The root value (with key='', path=[])
|
|
433
|
+
* - Every object property (with the property name as key)
|
|
434
|
+
* - Every array element (with the string index as key: '0', '1', etc.)
|
|
435
|
+
*
|
|
436
|
+
* @param root - The normalized `JsonValue` to transform
|
|
437
|
+
* @param replacer - The replacer function to apply
|
|
438
|
+
* @returns The transformed `JsonValue`
|
|
439
|
+
*/
|
|
440
|
+
function applyReplacer(root, replacer) {
|
|
441
|
+
const replacedRoot = replacer("", root, []);
|
|
442
|
+
if (replacedRoot === void 0) return transformChildren(root, replacer, []);
|
|
443
|
+
return transformChildren(normalizeValue(replacedRoot), replacer, []);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Recursively transforms the children of a `JsonValue` using the replacer.
|
|
447
|
+
*
|
|
448
|
+
* @param value - The value whose children should be transformed
|
|
449
|
+
* @param replacer - The replacer function to apply
|
|
450
|
+
* @param path - Current path from root
|
|
451
|
+
* @returns The value with transformed children
|
|
452
|
+
*/
|
|
453
|
+
function transformChildren(value, replacer, path) {
|
|
454
|
+
if (isJsonObject(value)) return transformObject(value, replacer, path);
|
|
455
|
+
if (isJsonArray(value)) return transformArray(value, replacer, path);
|
|
456
|
+
return value;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Transforms an object by applying the replacer to each property.
|
|
460
|
+
*
|
|
461
|
+
* @param obj - The object to transform
|
|
462
|
+
* @param replacer - The replacer function to apply
|
|
463
|
+
* @param path - Current path from root
|
|
464
|
+
* @returns A new object with transformed properties
|
|
465
|
+
*/
|
|
466
|
+
function transformObject(obj, replacer, path) {
|
|
467
|
+
const result = {};
|
|
468
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
469
|
+
const childPath = [...path, key];
|
|
470
|
+
const replacedValue = replacer(key, value, childPath);
|
|
471
|
+
if (replacedValue === void 0) continue;
|
|
472
|
+
result[key] = transformChildren(normalizeValue(replacedValue), replacer, childPath);
|
|
473
|
+
}
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Transforms an array by applying the replacer to each element.
|
|
478
|
+
*
|
|
479
|
+
* @param arr - The array to transform
|
|
480
|
+
* @param replacer - The replacer function to apply
|
|
481
|
+
* @param path - Current path from root
|
|
482
|
+
* @returns A new array with transformed elements
|
|
483
|
+
*/
|
|
484
|
+
function transformArray(arr, replacer, path) {
|
|
485
|
+
const result = [];
|
|
486
|
+
for (let i = 0; i < arr.length; i++) {
|
|
487
|
+
const value = arr[i];
|
|
488
|
+
const childPath = [...path, i];
|
|
489
|
+
const replacedValue = replacer(String(i), value, childPath);
|
|
490
|
+
if (replacedValue === void 0) continue;
|
|
491
|
+
const normalizedValue = normalizeValue(replacedValue);
|
|
492
|
+
result.push(transformChildren(normalizedValue, replacer, childPath));
|
|
493
|
+
}
|
|
494
|
+
return result;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Encodes a JavaScript value into TOON format string.
|
|
498
|
+
*
|
|
499
|
+
* @param input - Any JavaScript value (objects, arrays, primitives)
|
|
500
|
+
* @param options - Optional encoding configuration
|
|
501
|
+
* @returns TOON formatted string
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* encode({ name: 'Alice', age: 30 })
|
|
506
|
+
* // name: Alice
|
|
507
|
+
* // age: 30
|
|
508
|
+
*
|
|
509
|
+
* encode({ users: [{ id: 1 }, { id: 2 }] })
|
|
510
|
+
* // users[]:
|
|
511
|
+
* // - id: 1
|
|
512
|
+
* // - id: 2
|
|
513
|
+
*
|
|
514
|
+
* encode(data, { indent: 4, keyFolding: 'safe' })
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
function encode(input, options) {
|
|
518
|
+
return Array.from(encodeLines(input, options)).join("\n");
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Encodes a JavaScript value into TOON format as a sequence of lines.
|
|
522
|
+
*
|
|
523
|
+
* This function yields TOON lines one at a time without building the full string,
|
|
524
|
+
* making it suitable for streaming large outputs to files, HTTP responses, or process stdout.
|
|
525
|
+
*
|
|
526
|
+
* @param input - Any JavaScript value (objects, arrays, primitives)
|
|
527
|
+
* @param options - Optional encoding configuration
|
|
528
|
+
* @returns Iterable of TOON lines (without trailing newlines)
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```ts
|
|
532
|
+
* // Stream to stdout
|
|
533
|
+
* for (const line of encodeLines({ name: 'Alice', age: 30 })) {
|
|
534
|
+
* console.log(line)
|
|
535
|
+
* }
|
|
536
|
+
*
|
|
537
|
+
* // Collect to array
|
|
538
|
+
* const lines = Array.from(encodeLines(data))
|
|
539
|
+
*
|
|
540
|
+
* // Equivalent to encode()
|
|
541
|
+
* const toonString = Array.from(encodeLines(data, options)).join('\n')
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
function encodeLines(input, options) {
|
|
545
|
+
const normalizedValue = normalizeValue(input);
|
|
546
|
+
const resolvedOptions = resolveOptions(options);
|
|
547
|
+
return encodeJsonValue(resolvedOptions.replacer ? applyReplacer(normalizedValue, resolvedOptions.replacer) : normalizedValue, resolvedOptions, 0);
|
|
548
|
+
}
|
|
549
|
+
function resolveOptions(options) {
|
|
550
|
+
return {
|
|
551
|
+
indent: options?.indent ?? 2,
|
|
552
|
+
delimiter: options?.delimiter ?? DEFAULT_DELIMITER,
|
|
553
|
+
keyFolding: options?.keyFolding ?? "off",
|
|
554
|
+
flattenDepth: options?.flattenDepth ?? Number.POSITIVE_INFINITY,
|
|
555
|
+
replacer: options?.replacer
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
//#endregion
|
|
559
|
+
//#region src/output/format.ts
|
|
560
|
+
/**
|
|
561
|
+
* Format a result payload to stdout in one of three flavours:
|
|
562
|
+
*
|
|
563
|
+
* json (default) pretty JSON, agent-friendly and human-OK
|
|
564
|
+
* toon TOON (Token-Oriented Object Notation) — ~30-50% fewer
|
|
565
|
+
* tokens on uniform array-of-objects (LLM context optimization)
|
|
566
|
+
* table not implemented in 0.1.0 — falls back to pretty JSON
|
|
567
|
+
* (a v0.1.x target; pure cosmetic, doesn't affect agent flow)
|
|
568
|
+
*
|
|
569
|
+
* Errors / logs MUST NOT go through here — use stderr (console.error) so
|
|
570
|
+
* agents parsing stdout don't break.
|
|
571
|
+
*/
|
|
572
|
+
function writeResult(data, format = "json") {
|
|
573
|
+
const text = normalize(format) === "toon" ? encode(data) : JSON.stringify(data, null, 2);
|
|
574
|
+
process.stdout.write(text + "\n");
|
|
575
|
+
}
|
|
576
|
+
/** Print an error structurally to stdout (still parseable) and a hint to stderr. */
|
|
577
|
+
function writeError(error, format = "json") {
|
|
578
|
+
const payload = serializeError(error);
|
|
579
|
+
const text = normalize(format) === "toon" ? encode(payload) : JSON.stringify(payload, null, 2);
|
|
580
|
+
process.stdout.write(text + "\n");
|
|
581
|
+
const hint = payload.message;
|
|
582
|
+
if (hint) process.stderr.write(`error: ${hint}\n`);
|
|
583
|
+
}
|
|
584
|
+
function normalize(f) {
|
|
585
|
+
if (f === "toon") return "toon";
|
|
586
|
+
if (f === "table") return "table";
|
|
587
|
+
return "json";
|
|
588
|
+
}
|
|
589
|
+
function serializeError(error) {
|
|
590
|
+
if (error instanceof Error) return {
|
|
591
|
+
error: error.name,
|
|
592
|
+
message: error.message
|
|
593
|
+
};
|
|
594
|
+
if (error && typeof error === "object") {
|
|
595
|
+
const obj = error;
|
|
596
|
+
const errorKey = obj.code ?? obj.error ?? "UNKNOWN";
|
|
597
|
+
return {
|
|
598
|
+
error: errorKey,
|
|
599
|
+
message: obj.message ?? (obj.status != null ? `HTTP ${obj.status}` : null) ?? String(errorKey),
|
|
600
|
+
...obj.status != null ? { status: obj.status } : {},
|
|
601
|
+
...obj.body != null ? { details: obj.body } : {}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
error: "UNKNOWN",
|
|
606
|
+
message: String(error)
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
//#endregion
|
|
610
|
+
export { writeResult as n, writeError as t };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/output/headers.ts
|
|
2
|
+
function tenantProjectHeaders(active) {
|
|
3
|
+
return {
|
|
4
|
+
"X-Tenant-Id": active.tenantId,
|
|
5
|
+
"X-Tenant-Name": encodeURIComponent(active.tenantName),
|
|
6
|
+
"X-Project-Id": active.projectId,
|
|
7
|
+
"X-Project-Name": encodeURIComponent(active.projectName)
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { tenantProjectHeaders as t };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { a as resolveConfig } from "./device-flow-BgsZipYA.mjs";
|
|
2
|
+
import { t as xbApiFetch } from "./api-client-DwySN6x-.mjs";
|
|
3
|
+
import { n as writeResult, t as writeError } from "./format-BZvv8lYc.mjs";
|
|
4
|
+
import { t as requireActiveProject } from "./project-store-Bz5kf-EI.mjs";
|
|
5
|
+
import { n as mergeUserIds, r as toLocalDateTime, t as csvToArray } from "./util-DgwkUfV9.mjs";
|
|
6
|
+
import { t as tenantProjectHeaders } from "./headers-D79npewp.mjs";
|
|
7
|
+
import { defineCommand } from "citty";
|
|
8
|
+
//#region src/commands/audio/list.ts
|
|
9
|
+
/**
|
|
10
|
+
* `xiaobao-cli audio list` — page audio metadata via POST /ai-open/audio/page.
|
|
11
|
+
*
|
|
12
|
+
* Mirrors openclaw-xiaobao xiaobao_list_audio. Returns audio metadata only
|
|
13
|
+
* (audioId / fileId / startTime / endTime / duration / sale info / fileUrl).
|
|
14
|
+
* Transcript text comes from `xiaobao-cli audio text <audio-id>`.
|
|
15
|
+
*/
|
|
16
|
+
var list_default = defineCommand({
|
|
17
|
+
meta: {
|
|
18
|
+
name: "list",
|
|
19
|
+
description: "录音元数据分页查询(按时间范围 + 可选顾问过滤)"
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
from: {
|
|
23
|
+
type: "string",
|
|
24
|
+
required: true,
|
|
25
|
+
description: "录音开始时间,yyyy-MM-dd HH:mm:ss(或 ISO,自动转换)"
|
|
26
|
+
},
|
|
27
|
+
to: {
|
|
28
|
+
type: "string",
|
|
29
|
+
required: true,
|
|
30
|
+
description: "录音结束时间,同 from 格式"
|
|
31
|
+
},
|
|
32
|
+
"user-id": {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "单顾问 user-id 过滤"
|
|
35
|
+
},
|
|
36
|
+
"user-id-list": {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "CSV: u1,u2,u3 多顾问"
|
|
39
|
+
},
|
|
40
|
+
page: {
|
|
41
|
+
type: "string",
|
|
42
|
+
default: "1"
|
|
43
|
+
},
|
|
44
|
+
size: {
|
|
45
|
+
type: "string",
|
|
46
|
+
default: "10"
|
|
47
|
+
},
|
|
48
|
+
"api-base": { type: "string" },
|
|
49
|
+
"auth-base": { type: "string" },
|
|
50
|
+
format: {
|
|
51
|
+
type: "string",
|
|
52
|
+
default: "json"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
async run({ args }) {
|
|
56
|
+
try {
|
|
57
|
+
const config = resolveConfig({
|
|
58
|
+
apiBase: args["api-base"],
|
|
59
|
+
authBase: args["auth-base"]
|
|
60
|
+
});
|
|
61
|
+
const active = await requireActiveProject();
|
|
62
|
+
const mergedUserIds = mergeUserIds(args["user-id"], csvToArray(args["user-id-list"]));
|
|
63
|
+
writeResult(await xbApiFetch(config, "POST", "/ai-open/audio/page", {
|
|
64
|
+
headers: tenantProjectHeaders(active),
|
|
65
|
+
body: {
|
|
66
|
+
fromDate: toLocalDateTime(args.from),
|
|
67
|
+
toDate: toLocalDateTime(args.to),
|
|
68
|
+
userIdList: mergedUserIds,
|
|
69
|
+
page: Number(args.page),
|
|
70
|
+
size: Number(args.size)
|
|
71
|
+
}
|
|
72
|
+
}), args.format);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
writeError(err, args.format);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
//#endregion
|
|
80
|
+
export { list_default as default };
|