@thinkingai/ae-cli 1.0.22 → 1.0.27
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 +39 -1
- package/README.zh.md +40 -1
- package/dist/{auth-YM7OI23X.js → auth-TXFJHPXU.js} +3 -2
- package/dist/{auth-5S7SPPEJ.js → auth-W2JZ3DKA.js} +11 -4
- package/dist/{chunk-MPFTXJFG.js → chunk-2NGWYMLB.js} +14 -2
- package/dist/chunk-6T7245YE.js +478 -0
- package/dist/{chunk-KM57HI5B.js → chunk-B4UL2VIJ.js} +7 -1
- package/dist/{chunk-TMMUBSKW.js → chunk-BI5ZVD6T.js} +8 -1
- package/dist/chunk-MNHE6SSI.js +79 -0
- package/dist/chunk-MWWYGZ76.js +130 -0
- package/dist/{chunk-24ZKQWG2.js → chunk-SRRUNQIM.js} +51 -4
- package/dist/chunk-TG64AQV4.js +262 -0
- package/dist/{chunk-NBFTPIAH.js → chunk-VT6VC4PA.js} +15 -4
- package/dist/{client-7S23DVHH.js → client-IU2E5IOL.js} +6 -3
- package/dist/{config-RVUESJRF.js → config-WH3R3IRY.js} +3 -2
- package/dist/index.js +195 -20
- package/dist/model-CC7U5XOJ.js +131 -0
- package/dist/{raw-5SYAUCJQ.js → raw-TUHZQ4UB.js} +5 -4
- package/dist/sync-EVEDS7YE.js +383 -0
- package/dist/te-agent-FLTDYV3L.js +522 -0
- package/dist/{te-analysis-RQST6AT3.js → te-analysis-CMXADIJM.js} +101 -12
- package/dist/{te-audience-TJ74UJI3.js → te-audience-LPZFFSXM.js} +4 -3
- package/dist/{te-common-W5URM2SH.js → te-common-BXQFKTB3.js} +4 -3
- package/dist/{te-community-YRV2VAD4.js → te-community-K5S3VOZY.js} +4 -3
- package/dist/{te-dataops-ZPH72BCK.js → te-dataops-567IMCQG.js} +4 -3
- package/dist/{te-engage-57UKFV74.js → te-engage-TBUTGW5F.js} +105 -49
- package/dist/{te-kb-GD7SJRYB.js → te-kb-XHVBWP5E.js} +227 -38
- package/dist/{te-meta-25SLZFXJ.js → te-meta-NQ4U3VJW.js} +25 -4
- package/dist/te-team-556APRIU.js +529 -0
- package/package.json +6 -1
- package/skills/ae-agent/SKILL.md +133 -0
- package/skills/ae-analysis/references/create_entity.md +39 -0
- package/skills/ae-analysis/references/create_space.md +34 -0
- package/skills/ae-analysis/references/drilldown_user_events.md +1 -1
- package/skills/ae-analysis/references/drilldown_users.md +2 -2
- package/skills/ae-analysis/references/query_adhoc.md +3 -2
- package/skills/ae-analysis/references/query_entity_details.md +1 -1
- package/skills/ae-engage/SKILL.md +25 -2
- package/skills/ae-engage/references/build-task-save-guide.md +283 -0
- package/skills/ae-engage/references/save-task.md +304 -0
- package/skills/ae-kb/SKILL.md +283 -0
- package/skills/ae-team/SKILL.md +164 -0
- package/skills/ae-team/references/ai-generate.md +39 -0
- package/skills/ae-team/references/create.md +94 -0
- package/skills/ae-team/references/delete.md +39 -0
- package/skills/ae-team/references/list-projects.md +45 -0
- package/skills/ae-team/references/list-templates.md +38 -0
- package/skills/ae-team/references/list.md +39 -0
- package/skills/ae-team/references/run-artifacts.md +51 -0
- package/skills/ae-team/references/run-cancel.md +38 -0
- package/skills/ae-team/references/run-chat.md +57 -0
- package/skills/ae-team/references/run-reply.md +41 -0
- package/skills/ae-team/references/run-result.md +75 -0
- package/skills/ae-team/references/run-start.md +73 -0
- package/skills/ae-team/references/run-watch.md +82 -0
- package/skills/ae-team/references/update.md +47 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
// src/core/multiselect.ts
|
|
2
|
+
var MultiselectCancelled = class extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("\u7528\u6237\u53D6\u6D88\u9009\u62E9");
|
|
5
|
+
this.name = "MultiselectCancelled";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
function buildRows(items) {
|
|
9
|
+
const rows = [];
|
|
10
|
+
let lastGroup;
|
|
11
|
+
for (let i = 0; i < items.length; i++) {
|
|
12
|
+
const it = items[i];
|
|
13
|
+
if (it.group && it.group !== lastGroup) {
|
|
14
|
+
rows.push({ kind: "header", groupLabel: it.group });
|
|
15
|
+
lastGroup = it.group;
|
|
16
|
+
}
|
|
17
|
+
rows.push({ kind: "item", itemIndex: i, item: it });
|
|
18
|
+
}
|
|
19
|
+
return rows;
|
|
20
|
+
}
|
|
21
|
+
function promptMultiselect(opts) {
|
|
22
|
+
const { title, items } = opts;
|
|
23
|
+
if (items.length === 0) {
|
|
24
|
+
return Promise.resolve([]);
|
|
25
|
+
}
|
|
26
|
+
const stderr = process.stderr;
|
|
27
|
+
const stdin = process.stdin;
|
|
28
|
+
if (!stdin.isTTY) {
|
|
29
|
+
return Promise.reject(
|
|
30
|
+
new Error("ae-cli sync \u9700\u8981 TTY \u624D\u80FD\u8FDB\u884C\u591A\u9009\uFF1B\u8BF7\u5728\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\u4E2D\u8FD0\u884C")
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const rows = buildRows(items);
|
|
34
|
+
const itemRowIndices = [];
|
|
35
|
+
rows.forEach((r, idx) => {
|
|
36
|
+
if (r.kind === "item") itemRowIndices.push(idx);
|
|
37
|
+
});
|
|
38
|
+
const selected = /* @__PURE__ */ new Set();
|
|
39
|
+
items.forEach((it, idx) => {
|
|
40
|
+
if (it.preselected) selected.add(idx);
|
|
41
|
+
});
|
|
42
|
+
let cursorRowIdx = itemRowIndices[0];
|
|
43
|
+
let renderCount = 0;
|
|
44
|
+
function totalLines() {
|
|
45
|
+
return rows.length + 2;
|
|
46
|
+
}
|
|
47
|
+
function render() {
|
|
48
|
+
if (renderCount > 0) {
|
|
49
|
+
stderr.write(`\x1B[${totalLines()}A`);
|
|
50
|
+
}
|
|
51
|
+
stderr.write(`${title} (space \u9009\u62E9 \xB7 a \u5168\u9009/\u5168\u4E0D\u9009 \xB7 enter \u786E\u8BA4 \xB7 q \u53D6\u6D88)\x1B[K
|
|
52
|
+
`);
|
|
53
|
+
stderr.write(`\x1B[K
|
|
54
|
+
`);
|
|
55
|
+
rows.forEach((row, ridx) => {
|
|
56
|
+
if (row.kind === "header") {
|
|
57
|
+
stderr.write(` \x1B[90m\u2500\u2500 ${row.groupLabel} \u2500\u2500\x1B[0m\x1B[K
|
|
58
|
+
`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const isCursor = ridx === cursorRowIdx;
|
|
62
|
+
const isSelected = selected.has(row.itemIndex);
|
|
63
|
+
const pointer = isCursor ? "\x1B[36m\u276F\x1B[0m" : " ";
|
|
64
|
+
const checkbox = isSelected ? "\x1B[32m[x]\x1B[0m" : "[ ]";
|
|
65
|
+
const label = row.item.label;
|
|
66
|
+
const hint = row.item.hint ? ` \x1B[90m${row.item.hint}\x1B[0m` : "";
|
|
67
|
+
stderr.write(`${pointer} ${checkbox} ${label}${hint}\x1B[K
|
|
68
|
+
`);
|
|
69
|
+
});
|
|
70
|
+
renderCount++;
|
|
71
|
+
}
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
stderr.write("\x1B[?25l");
|
|
74
|
+
stdin.setRawMode(true);
|
|
75
|
+
stdin.resume();
|
|
76
|
+
stdin.setEncoding("utf8");
|
|
77
|
+
function cleanup() {
|
|
78
|
+
stdin.setRawMode(false);
|
|
79
|
+
stdin.pause();
|
|
80
|
+
stdin.removeListener("data", onData);
|
|
81
|
+
stderr.write("\x1B[?25h");
|
|
82
|
+
}
|
|
83
|
+
function moveCursor(direction) {
|
|
84
|
+
const cur = itemRowIndices.indexOf(cursorRowIdx);
|
|
85
|
+
const next = (cur + direction + itemRowIndices.length) % itemRowIndices.length;
|
|
86
|
+
cursorRowIdx = itemRowIndices[next];
|
|
87
|
+
render();
|
|
88
|
+
}
|
|
89
|
+
function toggleAll() {
|
|
90
|
+
if (selected.size === items.length) {
|
|
91
|
+
selected.clear();
|
|
92
|
+
} else {
|
|
93
|
+
items.forEach((_, idx) => selected.add(idx));
|
|
94
|
+
}
|
|
95
|
+
render();
|
|
96
|
+
}
|
|
97
|
+
function onData(key) {
|
|
98
|
+
if (key === "\x1B[A" || key === "k") {
|
|
99
|
+
moveCursor(-1);
|
|
100
|
+
} else if (key === "\x1B[B" || key === "j") {
|
|
101
|
+
moveCursor(1);
|
|
102
|
+
} else if (key === " ") {
|
|
103
|
+
const row = rows[cursorRowIdx];
|
|
104
|
+
if (row.kind === "item") {
|
|
105
|
+
const idx = row.itemIndex;
|
|
106
|
+
if (selected.has(idx)) selected.delete(idx);
|
|
107
|
+
else selected.add(idx);
|
|
108
|
+
render();
|
|
109
|
+
}
|
|
110
|
+
} else if (key === "a" || key === "A") {
|
|
111
|
+
toggleAll();
|
|
112
|
+
} else if (key === "\r" || key === "\n") {
|
|
113
|
+
if (selected.size === 0) {
|
|
114
|
+
stderr.write("\x07");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
cleanup();
|
|
118
|
+
const result = Array.from(selected).map((i) => items[i].value);
|
|
119
|
+
resolve(result);
|
|
120
|
+
} else if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
|
|
121
|
+
cleanup();
|
|
122
|
+
reject(new MultiselectCancelled());
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
stdin.on("data", onData);
|
|
126
|
+
render();
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function promptSingleCheckboxSelect(opts) {
|
|
130
|
+
const { title, items } = opts;
|
|
131
|
+
if (items.length === 0) return Promise.reject(new Error("\u65E0\u53EF\u9009\u9879"));
|
|
132
|
+
const stderr = process.stderr;
|
|
133
|
+
const stdin = process.stdin;
|
|
134
|
+
if (!stdin.isTTY) return Promise.reject(new Error("\u9700\u8981 TTY \u624D\u80FD\u8FDB\u884C\u5355\u9009"));
|
|
135
|
+
const preselectedIndex = items.findIndex((item) => item.preselected);
|
|
136
|
+
let cursor = preselectedIndex >= 0 ? preselectedIndex : 0;
|
|
137
|
+
let selected = preselectedIndex >= 0 ? preselectedIndex : null;
|
|
138
|
+
let renderCount = 0;
|
|
139
|
+
const lines = items.length + 2;
|
|
140
|
+
function render() {
|
|
141
|
+
if (renderCount > 0) stderr.write(`\x1B[${lines}A`);
|
|
142
|
+
stderr.write(`${title} (space \u9009\u62E9 \xB7 enter \u786E\u8BA4 \xB7 q \u53D6\u6D88)\x1B[K
|
|
143
|
+
`);
|
|
144
|
+
stderr.write(`\x1B[K
|
|
145
|
+
`);
|
|
146
|
+
items.forEach((it, idx) => {
|
|
147
|
+
const pointer = idx === cursor ? "\x1B[36m\u276F\x1B[0m" : " ";
|
|
148
|
+
const checkbox = selected === idx ? "\x1B[32m[x]\x1B[0m" : "[ ]";
|
|
149
|
+
const hint = it.hint ? ` \x1B[90m${it.hint}\x1B[0m` : "";
|
|
150
|
+
stderr.write(`${pointer} ${checkbox} ${it.label}${hint}\x1B[K
|
|
151
|
+
`);
|
|
152
|
+
});
|
|
153
|
+
renderCount++;
|
|
154
|
+
}
|
|
155
|
+
return new Promise((resolve, reject) => {
|
|
156
|
+
stderr.write("\x1B[?25l");
|
|
157
|
+
stdin.setRawMode(true);
|
|
158
|
+
stdin.resume();
|
|
159
|
+
stdin.setEncoding("utf8");
|
|
160
|
+
function cleanup() {
|
|
161
|
+
stdin.setRawMode(false);
|
|
162
|
+
stdin.pause();
|
|
163
|
+
stdin.removeListener("data", onData);
|
|
164
|
+
stderr.write("\x1B[?25h");
|
|
165
|
+
}
|
|
166
|
+
function moveCursor(direction) {
|
|
167
|
+
cursor = (cursor + direction + items.length) % items.length;
|
|
168
|
+
render();
|
|
169
|
+
}
|
|
170
|
+
function onData(key) {
|
|
171
|
+
if (key === "\x1B[A" || key === "k") {
|
|
172
|
+
moveCursor(-1);
|
|
173
|
+
} else if (key === "\x1B[B" || key === "j") {
|
|
174
|
+
moveCursor(1);
|
|
175
|
+
} else if (key === " ") {
|
|
176
|
+
selected = cursor;
|
|
177
|
+
render();
|
|
178
|
+
} else if (key === "\r" || key === "\n") {
|
|
179
|
+
if (selected === null) {
|
|
180
|
+
stderr.write("\x07");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
cleanup();
|
|
184
|
+
resolve(items[selected].value);
|
|
185
|
+
} else if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
|
|
186
|
+
cleanup();
|
|
187
|
+
reject(new MultiselectCancelled());
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
stdin.on("data", onData);
|
|
191
|
+
render();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function promptSingleSelect(opts) {
|
|
195
|
+
const { title, items } = opts;
|
|
196
|
+
if (items.length === 0) return Promise.reject(new Error("\u65E0\u53EF\u9009\u9879"));
|
|
197
|
+
const stderr = process.stderr;
|
|
198
|
+
const stdin = process.stdin;
|
|
199
|
+
if (!stdin.isTTY) return Promise.reject(new Error("\u9700\u8981 TTY \u624D\u80FD\u8FDB\u884C\u5355\u9009"));
|
|
200
|
+
let cursor = 0;
|
|
201
|
+
let renderCount = 0;
|
|
202
|
+
const lines = items.length + 1;
|
|
203
|
+
function render() {
|
|
204
|
+
if (renderCount > 0) stderr.write(`\x1B[${lines}A`);
|
|
205
|
+
stderr.write(`${title}\x1B[K
|
|
206
|
+
`);
|
|
207
|
+
items.forEach((it, idx) => {
|
|
208
|
+
const pointer = idx === cursor ? "\x1B[36m\u276F\x1B[0m" : " ";
|
|
209
|
+
stderr.write(`${pointer} ${it.label}\x1B[K
|
|
210
|
+
`);
|
|
211
|
+
});
|
|
212
|
+
renderCount++;
|
|
213
|
+
}
|
|
214
|
+
return new Promise((resolve, reject) => {
|
|
215
|
+
stderr.write("\x1B[?25l");
|
|
216
|
+
stdin.setRawMode(true);
|
|
217
|
+
stdin.resume();
|
|
218
|
+
stdin.setEncoding("utf8");
|
|
219
|
+
function cleanup() {
|
|
220
|
+
stdin.setRawMode(false);
|
|
221
|
+
stdin.pause();
|
|
222
|
+
stdin.removeListener("data", onData);
|
|
223
|
+
stderr.write("\x1B[?25h");
|
|
224
|
+
}
|
|
225
|
+
function onData(key) {
|
|
226
|
+
if (key === "\x1B[A" || key === "k") {
|
|
227
|
+
cursor = (cursor - 1 + items.length) % items.length;
|
|
228
|
+
render();
|
|
229
|
+
} else if (key === "\x1B[B" || key === "j") {
|
|
230
|
+
cursor = (cursor + 1) % items.length;
|
|
231
|
+
render();
|
|
232
|
+
} else if (key === "\r" || key === "\n") {
|
|
233
|
+
cleanup();
|
|
234
|
+
resolve(items[cursor].value);
|
|
235
|
+
} else if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
|
|
236
|
+
cleanup();
|
|
237
|
+
reject(new MultiselectCancelled());
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
stdin.on("data", onData);
|
|
241
|
+
render();
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/commands/sync/scanners.ts
|
|
246
|
+
import { createHash } from "crypto";
|
|
247
|
+
import { readdirSync, readFileSync as readFileSync2, statSync, lstatSync, existsSync as existsSync2, realpathSync } from "fs";
|
|
248
|
+
import { homedir } from "os";
|
|
249
|
+
import { basename, join, relative, sep } from "path";
|
|
250
|
+
|
|
251
|
+
// src/commands/sync/skill-manifest.ts
|
|
252
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
253
|
+
var SKILL_MANIFEST_FILE = ".skill-manifest.json";
|
|
254
|
+
function isSkillScope(value) {
|
|
255
|
+
return value === "personal" || value === "company" || value === "system";
|
|
256
|
+
}
|
|
257
|
+
function uniqueEntries(entries) {
|
|
258
|
+
const seen = /* @__PURE__ */ new Set();
|
|
259
|
+
const out = [];
|
|
260
|
+
for (const entry of entries) {
|
|
261
|
+
if (seen.has(entry.dirName)) continue;
|
|
262
|
+
seen.add(entry.dirName);
|
|
263
|
+
out.push(entry);
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
function readSkillManifestEntries(manifestPath) {
|
|
268
|
+
if (!existsSync(manifestPath)) return [];
|
|
269
|
+
let parsed;
|
|
270
|
+
try {
|
|
271
|
+
parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
272
|
+
} catch {
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
if (Array.isArray(parsed)) {
|
|
276
|
+
const entries = [];
|
|
277
|
+
for (const item of parsed) {
|
|
278
|
+
if (!item || typeof item !== "object") continue;
|
|
279
|
+
const entry = item;
|
|
280
|
+
if (typeof entry.dirName !== "string" || !isSkillScope(entry.scope))
|
|
281
|
+
continue;
|
|
282
|
+
entries.push({ dirName: entry.dirName, scope: entry.scope });
|
|
283
|
+
}
|
|
284
|
+
return uniqueEntries(entries);
|
|
285
|
+
}
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
function writeSkillManifestEntries(manifestPath, entries) {
|
|
289
|
+
writeFileSync(
|
|
290
|
+
manifestPath,
|
|
291
|
+
JSON.stringify(uniqueEntries(entries), null, 2) + "\n",
|
|
292
|
+
"utf8"
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/commands/sync/scanners.ts
|
|
297
|
+
var SECRET_PATTERN = /TOKEN|SECRET|KEY|PASSWORD/i;
|
|
298
|
+
function safeLstat(p) {
|
|
299
|
+
try {
|
|
300
|
+
return lstatSync(p);
|
|
301
|
+
} catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function safeReaddir(p) {
|
|
306
|
+
try {
|
|
307
|
+
return readdirSync(p);
|
|
308
|
+
} catch {
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function readSkillFile(filePath) {
|
|
313
|
+
try {
|
|
314
|
+
const content = readFileSync2(filePath, "utf8");
|
|
315
|
+
const stat = statSync(filePath);
|
|
316
|
+
return { content, mtime: stat.mtime };
|
|
317
|
+
} catch {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function sha256(content) {
|
|
322
|
+
return createHash("sha256").update(content).digest("hex");
|
|
323
|
+
}
|
|
324
|
+
function getCurrentWorkspace(home = process.env.HOME || homedir()) {
|
|
325
|
+
const cwd = process.cwd();
|
|
326
|
+
const wsRoot = join(home, "workspaces");
|
|
327
|
+
const rel = relative(wsRoot, cwd);
|
|
328
|
+
if (rel !== "" && !rel.startsWith("..") && !rel.startsWith(sep)) {
|
|
329
|
+
const name = rel.split(sep)[0];
|
|
330
|
+
return { dir: join(wsRoot, name), name };
|
|
331
|
+
}
|
|
332
|
+
if (existsSync2(join(cwd, ".claude"))) {
|
|
333
|
+
return { dir: cwd, name: basename(cwd) };
|
|
334
|
+
}
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
function readSkillScopeIndex(skillsRoot) {
|
|
338
|
+
const entries = readSkillManifestEntries(join(skillsRoot, SKILL_MANIFEST_FILE));
|
|
339
|
+
return new Map(entries.map((entry) => [entry.dirName, entry.scope]));
|
|
340
|
+
}
|
|
341
|
+
function scanSkillsInDir(dir, source, workspacePath) {
|
|
342
|
+
if (!existsSync2(dir)) return [];
|
|
343
|
+
const out = [];
|
|
344
|
+
const scopeIndex = readSkillScopeIndex(dir);
|
|
345
|
+
for (const slug of safeReaddir(dir)) {
|
|
346
|
+
const scope = scopeIndex.get(slug);
|
|
347
|
+
if (scope === "system" || scope === "company") continue;
|
|
348
|
+
const slugDir = join(dir, slug);
|
|
349
|
+
const lst = safeLstat(slugDir);
|
|
350
|
+
if (!lst) continue;
|
|
351
|
+
const isSymlink = lst.isSymbolicLink();
|
|
352
|
+
let isDir = lst.isDirectory();
|
|
353
|
+
if (isSymlink) {
|
|
354
|
+
try {
|
|
355
|
+
isDir = statSync(slugDir).isDirectory();
|
|
356
|
+
} catch {
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (!isDir) continue;
|
|
361
|
+
const filePath = join(slugDir, "SKILL.md");
|
|
362
|
+
if (!existsSync2(filePath)) continue;
|
|
363
|
+
const file = readSkillFile(filePath);
|
|
364
|
+
if (!file) continue;
|
|
365
|
+
out.push({
|
|
366
|
+
slug,
|
|
367
|
+
source,
|
|
368
|
+
workspacePath,
|
|
369
|
+
dirPath: slugDir,
|
|
370
|
+
filePath,
|
|
371
|
+
content: file.content,
|
|
372
|
+
checksum: sha256(file.content),
|
|
373
|
+
mtime: file.mtime.toISOString(),
|
|
374
|
+
isSymlink
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
return out;
|
|
378
|
+
}
|
|
379
|
+
function scanSkills() {
|
|
380
|
+
const home = process.env.HOME || homedir();
|
|
381
|
+
const workspace = getCurrentWorkspace(home);
|
|
382
|
+
if (!workspace) return [];
|
|
383
|
+
return scanSkillsInDir(join(workspace.dir, ".claude", "skills"), "workspace", workspace.name);
|
|
384
|
+
}
|
|
385
|
+
function readJsonSafe(p) {
|
|
386
|
+
try {
|
|
387
|
+
return JSON.parse(readFileSync2(p, "utf8"));
|
|
388
|
+
} catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function detectSecrets(env) {
|
|
393
|
+
if (!env) return false;
|
|
394
|
+
return Object.keys(env).some((k) => SECRET_PATTERN.test(k));
|
|
395
|
+
}
|
|
396
|
+
function parseMcpServers(servers, source, workspacePath, options = { filterScope: true }) {
|
|
397
|
+
if (!servers || typeof servers !== "object") return [];
|
|
398
|
+
const out = [];
|
|
399
|
+
for (const [slug, raw] of Object.entries(servers)) {
|
|
400
|
+
if (!raw || typeof raw !== "object") continue;
|
|
401
|
+
if (options.filterScope && (raw._scope === "system" || raw._scope === "company")) continue;
|
|
402
|
+
const transport = raw.type === "http" || raw.transport === "http" || typeof raw.url === "string" ? "http" : "stdio";
|
|
403
|
+
const env = raw.env && typeof raw.env === "object" ? raw.env : void 0;
|
|
404
|
+
const headers = raw.headers && typeof raw.headers === "object" ? raw.headers : void 0;
|
|
405
|
+
out.push({
|
|
406
|
+
slug,
|
|
407
|
+
source,
|
|
408
|
+
workspacePath,
|
|
409
|
+
transport,
|
|
410
|
+
url: typeof raw.url === "string" ? raw.url : void 0,
|
|
411
|
+
command: typeof raw.command === "string" ? raw.command : void 0,
|
|
412
|
+
args: Array.isArray(raw.args) ? raw.args.map(String) : void 0,
|
|
413
|
+
env,
|
|
414
|
+
headers,
|
|
415
|
+
hasSecrets: detectSecrets(env)
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
return out;
|
|
419
|
+
}
|
|
420
|
+
function normalizeProjectPath(p) {
|
|
421
|
+
const trimmed = p.replace(/\/+$/, "");
|
|
422
|
+
try {
|
|
423
|
+
return statSync(trimmed).isDirectory() ? realpathSync(trimmed).replace(/\/+$/, "") : trimmed;
|
|
424
|
+
} catch {
|
|
425
|
+
return trimmed;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function projectMcpServers(data, workspaceDir) {
|
|
429
|
+
const projects = data?.projects;
|
|
430
|
+
if (!projects || typeof projects !== "object") return void 0;
|
|
431
|
+
const normalizedWorkspaceDir = workspaceDir.replace(/\/+$/, "");
|
|
432
|
+
const project = projects[normalizedWorkspaceDir] || projects[`${normalizedWorkspaceDir}/`] || projects[process.cwd()] || projects[process.cwd().replace(/\/+$/, "")];
|
|
433
|
+
if (project && typeof project === "object") return project.mcpServers;
|
|
434
|
+
const realWorkspaceDir = normalizeProjectPath(workspaceDir);
|
|
435
|
+
for (const [projectPath, projectConfig] of Object.entries(projects)) {
|
|
436
|
+
if (normalizeProjectPath(projectPath) !== realWorkspaceDir) continue;
|
|
437
|
+
return projectConfig && typeof projectConfig === "object" ? projectConfig.mcpServers : void 0;
|
|
438
|
+
}
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
function scanMcps() {
|
|
442
|
+
const home = process.env.HOME || homedir();
|
|
443
|
+
const workspace = getCurrentWorkspace(home);
|
|
444
|
+
if (!workspace) return [];
|
|
445
|
+
const out = [];
|
|
446
|
+
const scopedMcpJson = readJsonSafe(join(workspace.dir, ".mcp.json"));
|
|
447
|
+
out.push(...parseMcpServers(scopedMcpJson?.mcpServers, "workspace", workspace.name, { filterScope: true }));
|
|
448
|
+
const workspaceClaudeJson = readJsonSafe(join(workspace.dir, ".claude", ".claude.json"));
|
|
449
|
+
out.push(
|
|
450
|
+
...parseMcpServers(projectMcpServers(workspaceClaudeJson, workspace.dir), "workspace", workspace.name, {
|
|
451
|
+
filterScope: false
|
|
452
|
+
})
|
|
453
|
+
);
|
|
454
|
+
const globalClaudeJson = readJsonSafe(join(home, ".claude.json"));
|
|
455
|
+
out.push(
|
|
456
|
+
...parseMcpServers(projectMcpServers(globalClaudeJson, workspace.dir), "global", void 0, {
|
|
457
|
+
filterScope: false
|
|
458
|
+
})
|
|
459
|
+
);
|
|
460
|
+
return out;
|
|
461
|
+
}
|
|
462
|
+
function describeSource(_c) {
|
|
463
|
+
return void 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
export {
|
|
467
|
+
MultiselectCancelled,
|
|
468
|
+
promptMultiselect,
|
|
469
|
+
promptSingleCheckboxSelect,
|
|
470
|
+
promptSingleSelect,
|
|
471
|
+
SKILL_MANIFEST_FILE,
|
|
472
|
+
readSkillManifestEntries,
|
|
473
|
+
writeSkillManifestEntries,
|
|
474
|
+
getCurrentWorkspace,
|
|
475
|
+
scanSkills,
|
|
476
|
+
scanMcps,
|
|
477
|
+
describeSource
|
|
478
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-MNHE6SSI.js";
|
|
4
|
+
|
|
1
5
|
// src/framework/output.ts
|
|
2
6
|
import Table from "cli-table3";
|
|
3
7
|
var KNOWN_ARRAY_FIELDS = [
|
|
@@ -95,7 +99,9 @@ function formatError(type, message, hint, code) {
|
|
|
95
99
|
return JSON.stringify(envelope, null, 2);
|
|
96
100
|
}
|
|
97
101
|
function printError(type, message, hint, code) {
|
|
98
|
-
|
|
102
|
+
const formatted = formatError(type, message, hint, code);
|
|
103
|
+
process.stderr.write(formatted + "\n");
|
|
104
|
+
logger.error(`[${type}] ${message}${hint ? " | " + hint : ""}`);
|
|
99
105
|
}
|
|
100
106
|
function printOutput(data, format, jqExpr) {
|
|
101
107
|
process.stdout.write(formatOutput(data, format, jqExpr) + "\n");
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-MNHE6SSI.js";
|
|
4
|
+
|
|
1
5
|
// src/core/json-utils.ts
|
|
2
6
|
import fs from "fs";
|
|
3
7
|
import { createRequire } from "module";
|
|
@@ -18,7 +22,7 @@ import path from "path";
|
|
|
18
22
|
var CONFIG_DIR = path.join(process.env.HOME || "", ".ae-cli");
|
|
19
23
|
var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
20
24
|
var MCP_TOKENS_FILE = path.join(CONFIG_DIR, "mcp-tokens.json");
|
|
21
|
-
var FALLBACK_MCP_TOKEN_FILE = "/
|
|
25
|
+
var FALLBACK_MCP_TOKEN_FILE = "/home/ta/te_agent_ta/.ae-config/mcp-token.json";
|
|
22
26
|
function ensureDir() {
|
|
23
27
|
if (!fs2.existsSync(CONFIG_DIR)) fs2.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
24
28
|
}
|
|
@@ -78,11 +82,13 @@ function loadConfig() {
|
|
|
78
82
|
`);
|
|
79
83
|
process.stderr.write(`[ae-cli] MCP tokens migrated from ${FALLBACK_MCP_TOKEN_FILE}
|
|
80
84
|
`);
|
|
85
|
+
logger.info(`MCP tokens migrated from fallback: activeHost=${activeHost}, hosts=${Object.keys(hosts).length}`);
|
|
81
86
|
const config = { activeHost, hosts };
|
|
82
87
|
saveConfig(config);
|
|
83
88
|
return config;
|
|
84
89
|
}
|
|
85
90
|
} catch (err) {
|
|
91
|
+
logger.error(`Error loading config: ${err.message}`);
|
|
86
92
|
console.error(`Error loading config: ${err.message}`);
|
|
87
93
|
}
|
|
88
94
|
return { activeHost: "", hosts: {} };
|
|
@@ -105,6 +111,7 @@ function migrateConfig(old) {
|
|
|
105
111
|
function saveConfig(config) {
|
|
106
112
|
ensureDir();
|
|
107
113
|
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
114
|
+
logger.info(`Config saved: activeHost=${config.activeHost}, hosts=${Object.keys(config.hosts).length}`);
|
|
108
115
|
}
|
|
109
116
|
function getActiveHost() {
|
|
110
117
|
const config = loadConfig();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// src/core/logger.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
var LOG_DIR = path.join(process.env.HOME || "", ".ae-cli", "log");
|
|
5
|
+
var Logger = class {
|
|
6
|
+
logDir;
|
|
7
|
+
date;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.logDir = LOG_DIR;
|
|
10
|
+
this.date = this.today();
|
|
11
|
+
this.ensureDir();
|
|
12
|
+
}
|
|
13
|
+
today() {
|
|
14
|
+
const d = /* @__PURE__ */ new Date();
|
|
15
|
+
return `${d.getFullYear()}${String(d.getMonth() + 1).padStart(2, "0")}${String(d.getDate()).padStart(2, "0")}`;
|
|
16
|
+
}
|
|
17
|
+
timestamp() {
|
|
18
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").split(".")[0];
|
|
19
|
+
}
|
|
20
|
+
ensureDir() {
|
|
21
|
+
if (!fs.existsSync(this.logDir)) {
|
|
22
|
+
fs.mkdirSync(this.logDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
filePath(level) {
|
|
26
|
+
const today = this.today();
|
|
27
|
+
if (today !== this.date) {
|
|
28
|
+
this.date = today;
|
|
29
|
+
}
|
|
30
|
+
return path.join(this.logDir, `${this.date}_${level}.log`);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 写入日志到文件(不输出到控制台,控制台由现有 process.stderr.write 负责)
|
|
34
|
+
*/
|
|
35
|
+
write(level, message) {
|
|
36
|
+
const ts = this.timestamp();
|
|
37
|
+
const line = `[${ts}] ${message}
|
|
38
|
+
`;
|
|
39
|
+
try {
|
|
40
|
+
fs.appendFileSync(this.filePath(level), line);
|
|
41
|
+
} catch {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** 常规操作日志 */
|
|
45
|
+
info(message) {
|
|
46
|
+
this.write("info", message);
|
|
47
|
+
}
|
|
48
|
+
/** 警告日志 */
|
|
49
|
+
warn(message) {
|
|
50
|
+
this.write("warning", message);
|
|
51
|
+
}
|
|
52
|
+
/** 错误日志 */
|
|
53
|
+
error(message) {
|
|
54
|
+
this.write("error", message);
|
|
55
|
+
}
|
|
56
|
+
/** 记录 HTTP API 请求详情 */
|
|
57
|
+
api(method, url, status, reqBody, respBody) {
|
|
58
|
+
const parts = [`API ${method} ${url} \u2192 HTTP ${status}`];
|
|
59
|
+
if (reqBody !== void 0 && reqBody !== null) {
|
|
60
|
+
const s = typeof reqBody === "string" ? reqBody : JSON.stringify(reqBody);
|
|
61
|
+
parts.push(`REQ: ${s.slice(0, 500)}`);
|
|
62
|
+
}
|
|
63
|
+
if (respBody !== void 0 && respBody !== null) {
|
|
64
|
+
const s = typeof respBody === "string" ? respBody : JSON.stringify(respBody);
|
|
65
|
+
parts.push(`RESP: ${s.slice(0, 500)}`);
|
|
66
|
+
}
|
|
67
|
+
this.info(parts.join(" | "));
|
|
68
|
+
}
|
|
69
|
+
/** 记录命令执行 */
|
|
70
|
+
command(name, args) {
|
|
71
|
+
const filtered = Object.entries(args).filter(([, v]) => v !== void 0 && v !== null && v !== "").map(([k, v]) => `--${k}=${JSON.stringify(v)}`).join(" ");
|
|
72
|
+
this.info(`CMD ${name}${filtered ? " " + filtered : ""}`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var logger = new Logger();
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
logger
|
|
79
|
+
};
|