@thinkingai/ae-cli 1.0.24 → 1.0.28
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 +17 -2
- package/README.zh.md +18 -2
- package/dist/auth-5NSDQFQB.js +454 -0
- package/dist/{auth-4OPL4YWG.js → auth-H2376DEF.js} +2 -2
- package/dist/chunk-AD5V3ZPJ.js +217 -0
- package/dist/chunk-CAQYQA4R.js +399 -0
- package/dist/{chunk-JJCRURTR.js → chunk-CLJF7MQA.js} +1 -1
- package/dist/chunk-GSJGPNKK.js +49 -0
- package/dist/chunk-IMBKVXKY.js +478 -0
- package/dist/chunk-KAEZTSXN.js +99 -0
- package/dist/{chunk-MZW6NOVS.js → chunk-LU7SXK4Q.js} +27 -8
- package/dist/chunk-OJDNO5QY.js +63 -0
- package/dist/{chunk-DC66L5AM.js → chunk-SRJIAOBN.js} +76 -91
- package/dist/{chunk-OVHL4JAC.js → chunk-WCHI7725.js} +44 -47
- package/dist/{client-TDH6MUWM.js → client-FCMK3XEK.js} +5 -3
- package/dist/config-64G36TJL.js +130 -0
- package/dist/index.js +50 -17
- package/dist/model-EZ6K7FXI.js +134 -0
- package/dist/{raw-EM7AP3RT.js → raw-VEF3D6UD.js} +11 -6
- package/dist/sync-NRODEVNH.js +385 -0
- package/dist/te-agent-7U7JLJKU.js +524 -0
- package/dist/{te-analysis-3KFSNUCJ.js → te-analysis-A2OSGHQ4.js} +136 -20
- package/dist/{te-audience-GMYJFCSC.js → te-audience-LI67PPGO.js} +5 -4
- package/dist/{te-common-YLERCMQI.js → te-common-35WVU3C5.js} +19 -8
- package/dist/{te-community-PYDN5A6B.js → te-community-LEAP6PWT.js} +4 -3
- package/dist/{te-dataops-ETWS5O3X.js → te-dataops-N2LGZBOX.js} +4 -3
- package/dist/{te-engage-ROJVZHDA.js → te-engage-H7C72Z46.js} +105 -49
- package/dist/{te-kb-VUNS2CC7.js → te-kb-I2OKTBAI.js} +225 -29
- package/dist/{te-meta-3EFWLM3A.js → te-meta-HBTIEDRO.js} +4 -3
- package/dist/te-team-EM5OWRQL.js +529 -0
- package/package.json +10 -2
- package/skills/ae-agent/SKILL.md +134 -0
- package/skills/ae-analysis/SKILL.md +1 -1
- 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/list_clusters.md +4 -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-analysis-global/SKILL.md +51 -0
- package/skills/ae-analysis-global/references/list_query_clusters.md +67 -0
- package/skills/ae-community/SKILL.md +2 -3
- package/skills/ae-dataops/SKILL.md +1 -2
- package/skills/ae-engage/SKILL.md +26 -2
- package/skills/ae-engage/references/add-approver.md +0 -1
- package/skills/ae-engage/references/add-channel.md +0 -1
- package/skills/ae-engage/references/approver-list.md +0 -1
- package/skills/ae-engage/references/build-task-save-guide.md +283 -0
- package/skills/ae-engage/references/cancel-query-by-request-id.md +0 -1
- package/skills/ae-engage/references/channel-detail.md +0 -1
- package/skills/ae-engage/references/channel-list.md +0 -1
- package/skills/ae-engage/references/config-channel-detail.md +0 -1
- package/skills/ae-engage/references/config-channel-list.md +0 -1
- package/skills/ae-engage/references/config-item-analysis-report.md +0 -1
- package/skills/ae-engage/references/config-item-detail.md +0 -1
- package/skills/ae-engage/references/config-item-list.md +0 -1
- package/skills/ae-engage/references/config-item-strategy-comparison.md +0 -1
- package/skills/ae-engage/references/config-item-trigger-report.md +0 -1
- package/skills/ae-engage/references/copy-config-template.md +0 -1
- package/skills/ae-engage/references/delete-channel.md +0 -1
- package/skills/ae-engage/references/delete-config-channel.md +0 -1
- package/skills/ae-engage/references/delete-config-item.md +0 -1
- package/skills/ae-engage/references/delete-flow.md +0 -1
- package/skills/ae-engage/references/flow-ab-split-node-report.md +0 -1
- package/skills/ae-engage/references/flow-detail.md +0 -1
- package/skills/ae-engage/references/flow-list.md +0 -1
- package/skills/ae-engage/references/flow-node-config-schema.md +0 -1
- package/skills/ae-engage/references/flow-node-detail-report.md +0 -1
- package/skills/ae-engage/references/flow-node-overview-report.md +0 -1
- package/skills/ae-engage/references/flow-process-report.md +0 -1
- package/skills/ae-engage/references/manage-flow.md +0 -1
- package/skills/ae-engage/references/manage-strategy.md +0 -1
- package/skills/ae-engage/references/manage-task.md +0 -1
- package/skills/ae-engage/references/modify-flow-base-info.md +0 -1
- package/skills/ae-engage/references/save-task.md +304 -0
- package/skills/ae-engage/references/strategy-detail.md +0 -1
- package/skills/ae-engage/references/strategy-list.md +0 -1
- package/skills/ae-engage/references/task-data-detail.md +0 -1
- package/skills/ae-engage/references/task-data-overview.md +0 -1
- package/skills/ae-engage/references/task-detail.md +0 -1
- package/skills/ae-engage/references/task-experiment-report.md +0 -1
- package/skills/ae-engage/references/task-list.md +0 -1
- package/skills/ae-engage/references/task-metric-detail.md +0 -1
- package/skills/ae-engage/references/task-stats.md +0 -1
- package/skills/ae-engage/references/update-channel-status.md +0 -1
- package/skills/ae-engage/references/update-config-channel-status.md +0 -1
- package/skills/ae-engage/references/validate-flow-node-config.md +0 -1
- package/skills/ae-engage/references/whitelist-list.md +0 -1
- package/skills/ae-kb/SKILL.md +284 -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
- package/dist/auth-PBPAZQWP.js +0 -168
- package/dist/chunk-47MTN54I.js +0 -285
- package/dist/config-5ELRYAIH.js +0 -257
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
// src/core/multiselect.ts
|
|
2
|
+
var MultiselectCancelled = class extends Error {
|
|
3
|
+
constructor() {
|
|
4
|
+
super("Selection cancelled by user");
|
|
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 requires a TTY for multi-select; please run in an interactive terminal")
|
|
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: select \xB7 a: select all/none \xB7 enter: confirm \xB7 q: cancel)\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("No items to select"));
|
|
132
|
+
const stderr = process.stderr;
|
|
133
|
+
const stdin = process.stdin;
|
|
134
|
+
if (!stdin.isTTY) return Promise.reject(new Error("A TTY is required for single-select"));
|
|
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: select \xB7 enter: confirm \xB7 q: cancel)\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("No items to select"));
|
|
197
|
+
const stderr = process.stderr;
|
|
198
|
+
const stdin = process.stdin;
|
|
199
|
+
if (!stdin.isTTY) return Promise.reject(new Error("A TTY is required for single-select"));
|
|
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
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSandboxRuntimeRoot
|
|
3
|
+
} from "./chunk-SRJIAOBN.js";
|
|
4
|
+
|
|
5
|
+
// src/core/te-agent-credentials.ts
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
function getCredentialsPath() {
|
|
10
|
+
return join(process.env.HOME || homedir(), ".te-agent", "credentials.json");
|
|
11
|
+
}
|
|
12
|
+
function getPersistentEnvPath() {
|
|
13
|
+
return join(getSandboxRuntimeRoot(), ".env");
|
|
14
|
+
}
|
|
15
|
+
function parseDotEnv(raw) {
|
|
16
|
+
const result = {};
|
|
17
|
+
for (const line of raw.split("\n")) {
|
|
18
|
+
if (/^\s*#/.test(line) || line.trim() === "") continue;
|
|
19
|
+
const match = /^\s*([^=]+)=(.*)$/.exec(line);
|
|
20
|
+
if (!match) continue;
|
|
21
|
+
const key = match[1].trim();
|
|
22
|
+
let value = match[2].trim();
|
|
23
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
24
|
+
value = value.slice(1, -1).replace(/\\"/g, '"');
|
|
25
|
+
}
|
|
26
|
+
if (value !== "") result[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
function readPersistentEnv() {
|
|
31
|
+
const envPath = getPersistentEnvPath();
|
|
32
|
+
try {
|
|
33
|
+
const raw = readFileSync(envPath, "utf8");
|
|
34
|
+
return parseDotEnv(raw);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err?.code === "ENOENT") return null;
|
|
37
|
+
throw new TeAgentCredentialsError(
|
|
38
|
+
`Failed to read ${envPath}: ${err?.message ?? err}`,
|
|
39
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
var TeAgentCredentialsError = class extends Error {
|
|
44
|
+
constructor(message, hint) {
|
|
45
|
+
super(message);
|
|
46
|
+
this.hint = hint;
|
|
47
|
+
this.name = "TeAgentCredentialsError";
|
|
48
|
+
}
|
|
49
|
+
hint;
|
|
50
|
+
};
|
|
51
|
+
function readLegacyCredentials() {
|
|
52
|
+
const credPath = getCredentialsPath();
|
|
53
|
+
try {
|
|
54
|
+
const raw = readFileSync(credPath, "utf8");
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
const main = parsed?.mainApp;
|
|
57
|
+
return main && typeof main === "object" ? main : null;
|
|
58
|
+
} catch (err) {
|
|
59
|
+
if (err?.code === "ENOENT") return null;
|
|
60
|
+
if (err instanceof SyntaxError) {
|
|
61
|
+
throw new TeAgentCredentialsError(
|
|
62
|
+
`Failed to parse ${credPath}: ${err.message}`,
|
|
63
|
+
"The credentials file may be corrupted; alternatively inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
throw new TeAgentCredentialsError(
|
|
67
|
+
`Failed to read ${credPath}: ${err?.message ?? err}`,
|
|
68
|
+
"Check file permissions, or inject runtime credentials via TE_CLAUDE_BASE_URL / SANDBOX_ID / SECRET_KEY"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function tryLoadTeAgentSandboxCredentials() {
|
|
73
|
+
const legacy = readLegacyCredentials();
|
|
74
|
+
const persistent = readPersistentEnv();
|
|
75
|
+
const url = process.env.TE_CLAUDE_BASE_URL || persistent?.TE_CLAUDE_BASE_URL || legacy?.url;
|
|
76
|
+
if (typeof url !== "string" || !url) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const sandboxId = process.env.SANDBOX_ID || persistent?.SANDBOX_ID || legacy?.sandboxId || null;
|
|
80
|
+
const sandboxSecretKey = process.env.SECRET_KEY || process.env.SANDBOX_SECRET_KEY || persistent?.SECRET_KEY || persistent?.SANDBOX_SECRET_KEY || legacy?.sandboxSecretKey || legacy?.secretKey || null;
|
|
81
|
+
return {
|
|
82
|
+
url,
|
|
83
|
+
sandboxId: typeof sandboxId === "string" ? sandboxId : null,
|
|
84
|
+
sandboxSecretKey: typeof sandboxSecretKey === "string" ? sandboxSecretKey : null
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function getClaudeConfigDir() {
|
|
88
|
+
const fromEnv = process.env.CLAUDE_CONFIG_DIR;
|
|
89
|
+
if (typeof fromEnv === "string" && fromEnv.length > 0) {
|
|
90
|
+
return fromEnv;
|
|
91
|
+
}
|
|
92
|
+
return join(homedir(), ".claude");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
TeAgentCredentialsError,
|
|
97
|
+
tryLoadTeAgentSandboxCredentials,
|
|
98
|
+
getClaudeConfigDir
|
|
99
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SecureStoreAuthError,
|
|
2
3
|
clearToken,
|
|
3
4
|
getToken,
|
|
4
5
|
resolveHost
|
|
5
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CAQYQA4R.js";
|
|
6
7
|
import {
|
|
7
8
|
logger,
|
|
8
9
|
safeJsonParse
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SRJIAOBN.js";
|
|
10
11
|
|
|
11
12
|
// src/core/client.ts
|
|
12
13
|
import WebSocket from "ws";
|
|
@@ -43,9 +44,16 @@ async function request(method, modulePath, params = {}, body = null, retry = tru
|
|
|
43
44
|
const text = await resp.text();
|
|
44
45
|
const data = safeJsonParse(text);
|
|
45
46
|
logger.api(method, url, resp.status, body, data);
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
if (resp.status === 401) {
|
|
48
|
+
if (retry) {
|
|
49
|
+
clearToken(resolvedHost);
|
|
50
|
+
return request(method, modulePath, params, body, false, resolvedHost);
|
|
51
|
+
}
|
|
52
|
+
throw new SecureStoreAuthError(`Session expired or unauthorized for ${resolvedHost}. Please run: ae-cli auth login`);
|
|
53
|
+
}
|
|
54
|
+
if (resp.status === 403) {
|
|
55
|
+
const m = data && typeof data === "object" && typeof data.error === "string" ? data.error : "Permission denied";
|
|
56
|
+
throw new Error(m);
|
|
49
57
|
}
|
|
50
58
|
if (data.return_code === -1001 && retry) {
|
|
51
59
|
clearToken(resolvedHost);
|
|
@@ -62,6 +70,9 @@ async function httpGet(modulePath, params = {}, hostUrl) {
|
|
|
62
70
|
async function httpPost(modulePath, params = {}, body, hostUrl) {
|
|
63
71
|
return request("POST", modulePath, params, body ?? {}, true, hostUrl);
|
|
64
72
|
}
|
|
73
|
+
async function httpRequest(method, modulePath, params = {}, body, hostUrl) {
|
|
74
|
+
return request(method.toUpperCase(), modulePath, params, body ?? {}, true, hostUrl);
|
|
75
|
+
}
|
|
65
76
|
async function httpDelete(modulePath, params = {}, body, hostUrl) {
|
|
66
77
|
return request("DELETE", modulePath, params, body ?? null, true, hostUrl);
|
|
67
78
|
}
|
|
@@ -76,9 +87,16 @@ async function uploadRequest(modulePath, form, params = {}, retry = true, hostUr
|
|
|
76
87
|
const text = await resp.text();
|
|
77
88
|
const data = safeJsonParse(text);
|
|
78
89
|
logger.api("POST", url, resp.status, { upload: true }, data);
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
90
|
+
if (resp.status === 401) {
|
|
91
|
+
if (retry) {
|
|
92
|
+
clearToken(resolvedHost);
|
|
93
|
+
return uploadRequest(modulePath, form, params, false, resolvedHost);
|
|
94
|
+
}
|
|
95
|
+
throw new SecureStoreAuthError(`Session expired or unauthorized for ${resolvedHost}. Please run: ae-cli auth login`);
|
|
96
|
+
}
|
|
97
|
+
if (resp.status === 403) {
|
|
98
|
+
const m = data && typeof data === "object" && typeof data.error === "string" ? data.error : "Permission denied";
|
|
99
|
+
throw new Error(m);
|
|
82
100
|
}
|
|
83
101
|
if (data.return_code === -1001 && retry) {
|
|
84
102
|
clearToken(resolvedHost);
|
|
@@ -175,6 +193,7 @@ async function queryReportData(projectId, reportId, qp, eventModel, options = {}
|
|
|
175
193
|
export {
|
|
176
194
|
httpGet,
|
|
177
195
|
httpPost,
|
|
196
|
+
httpRequest,
|
|
178
197
|
httpDelete,
|
|
179
198
|
httpUpload,
|
|
180
199
|
wsQuery,
|