@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,385 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MultiselectCancelled,
|
|
3
|
+
SKILL_MANIFEST_FILE,
|
|
4
|
+
describeSource,
|
|
5
|
+
getCurrentWorkspace,
|
|
6
|
+
promptMultiselect,
|
|
7
|
+
promptSingleSelect,
|
|
8
|
+
readSkillManifestEntries,
|
|
9
|
+
scanMcps,
|
|
10
|
+
scanSkills,
|
|
11
|
+
writeSkillManifestEntries
|
|
12
|
+
} from "./chunk-IMBKVXKY.js";
|
|
13
|
+
import {
|
|
14
|
+
TeAgentApiError,
|
|
15
|
+
getSandboxSyncPullCandidates,
|
|
16
|
+
postSandboxSyncPull,
|
|
17
|
+
postToMainApp
|
|
18
|
+
} from "./chunk-AD5V3ZPJ.js";
|
|
19
|
+
import {
|
|
20
|
+
TeAgentCredentialsError
|
|
21
|
+
} from "./chunk-KAEZTSXN.js";
|
|
22
|
+
import {
|
|
23
|
+
printError
|
|
24
|
+
} from "./chunk-CLJF7MQA.js";
|
|
25
|
+
import "./chunk-SRJIAOBN.js";
|
|
26
|
+
|
|
27
|
+
// src/commands/sync/index.ts
|
|
28
|
+
import Table from "cli-table3";
|
|
29
|
+
|
|
30
|
+
// src/commands/sync/local-copy.ts
|
|
31
|
+
import {
|
|
32
|
+
cpSync,
|
|
33
|
+
existsSync,
|
|
34
|
+
mkdirSync,
|
|
35
|
+
realpathSync,
|
|
36
|
+
rmSync,
|
|
37
|
+
statSync
|
|
38
|
+
} from "fs";
|
|
39
|
+
import path from "path";
|
|
40
|
+
var SKILL_SLUG_RE = /^[a-z0-9-]+$/;
|
|
41
|
+
function updateSkillManifestForSource(sourceDir, slug) {
|
|
42
|
+
if (!SKILL_SLUG_RE.test(slug)) {
|
|
43
|
+
throw new Error(`Invalid Skill slug: ${slug}`);
|
|
44
|
+
}
|
|
45
|
+
const sourceAbs = path.resolve(sourceDir);
|
|
46
|
+
if (!statSync(sourceAbs).isDirectory()) {
|
|
47
|
+
throw new Error(`Skill source path is not a directory: ${sourceDir}`);
|
|
48
|
+
}
|
|
49
|
+
const manifestPath = path.join(path.dirname(sourceAbs), SKILL_MANIFEST_FILE);
|
|
50
|
+
const manifest = readSkillManifestEntries(manifestPath);
|
|
51
|
+
const nextEntry = { dirName: slug, scope: "personal" };
|
|
52
|
+
const existingIndex = manifest.findIndex((entry) => entry.dirName === slug);
|
|
53
|
+
if (existingIndex >= 0 && manifest[existingIndex].scope === nextEntry.scope) {
|
|
54
|
+
return { manifestPath, changed: false };
|
|
55
|
+
}
|
|
56
|
+
const nextManifest = manifest.slice();
|
|
57
|
+
if (existingIndex >= 0) {
|
|
58
|
+
nextManifest[existingIndex] = nextEntry;
|
|
59
|
+
} else {
|
|
60
|
+
nextManifest.push(nextEntry);
|
|
61
|
+
}
|
|
62
|
+
writeSkillManifestEntries(manifestPath, nextManifest);
|
|
63
|
+
return { manifestPath, changed: true };
|
|
64
|
+
}
|
|
65
|
+
function copySkillPackageToTarget(args) {
|
|
66
|
+
if (!SKILL_SLUG_RE.test(args.slug)) {
|
|
67
|
+
throw new Error(`Invalid Skill slug: ${args.slug}`);
|
|
68
|
+
}
|
|
69
|
+
if (!path.isAbsolute(args.targetRoot)) {
|
|
70
|
+
throw new Error(`skillTargetRoot must be an absolute path: ${args.targetRoot}`);
|
|
71
|
+
}
|
|
72
|
+
const sourceReal = realpathSync(args.sourceDir);
|
|
73
|
+
if (!statSync(sourceReal).isDirectory()) {
|
|
74
|
+
throw new Error(`Skill source path is not a directory: ${args.sourceDir}`);
|
|
75
|
+
}
|
|
76
|
+
const targetDir = path.join(args.targetRoot, args.slug);
|
|
77
|
+
const targetAbs = path.resolve(targetDir);
|
|
78
|
+
if (targetAbs === sourceReal || targetAbs.startsWith(`${sourceReal}${path.sep}`)) {
|
|
79
|
+
return { targetDir, skipped: true };
|
|
80
|
+
}
|
|
81
|
+
if (existsSync(targetDir)) {
|
|
82
|
+
const targetReal = realpathSync(targetDir);
|
|
83
|
+
if (targetReal === sourceReal) {
|
|
84
|
+
return { targetDir, skipped: true };
|
|
85
|
+
}
|
|
86
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
87
|
+
}
|
|
88
|
+
mkdirSync(args.targetRoot, { recursive: true });
|
|
89
|
+
cpSync(sourceReal, targetDir, { recursive: true, dereference: true });
|
|
90
|
+
return { targetDir, skipped: false };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/commands/sync/index.ts
|
|
94
|
+
function redactEnv(env) {
|
|
95
|
+
if (!env) return void 0;
|
|
96
|
+
const out = {};
|
|
97
|
+
for (const [k, v] of Object.entries(env)) {
|
|
98
|
+
if (/TOKEN|SECRET|KEY|PASSWORD/i.test(k)) {
|
|
99
|
+
out[k] = "***";
|
|
100
|
+
} else {
|
|
101
|
+
out[k] = v;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
function skillToItem(s) {
|
|
107
|
+
return {
|
|
108
|
+
kind: "skill",
|
|
109
|
+
slug: s.slug,
|
|
110
|
+
scope: "personal",
|
|
111
|
+
source: s.source,
|
|
112
|
+
workspacePath: s.workspacePath,
|
|
113
|
+
event: "upsert",
|
|
114
|
+
dirPath: s.dirPath,
|
|
115
|
+
content: s.content,
|
|
116
|
+
checksum: s.checksum,
|
|
117
|
+
mtime: s.mtime
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function mcpToItem(m, includeSecrets) {
|
|
121
|
+
return {
|
|
122
|
+
kind: "mcp",
|
|
123
|
+
slug: m.slug,
|
|
124
|
+
scope: "personal",
|
|
125
|
+
source: m.source,
|
|
126
|
+
workspacePath: m.workspacePath,
|
|
127
|
+
event: "upsert",
|
|
128
|
+
transport: m.transport,
|
|
129
|
+
url: m.url,
|
|
130
|
+
command: m.command,
|
|
131
|
+
args: m.args,
|
|
132
|
+
env: includeSecrets ? m.env : redactEnv(m.env),
|
|
133
|
+
headers: m.headers
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function selectSkills() {
|
|
137
|
+
const all = scanSkills();
|
|
138
|
+
if (all.length === 0) {
|
|
139
|
+
process.stderr.write("No Skills found (scanned current workspace .claude/skills)\n");
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
all.sort((a, b) => {
|
|
143
|
+
if (a.source !== b.source) return a.source === "global" ? -1 : 1;
|
|
144
|
+
return a.slug.localeCompare(b.slug);
|
|
145
|
+
});
|
|
146
|
+
const items = all.map((s) => ({
|
|
147
|
+
value: s,
|
|
148
|
+
label: s.slug,
|
|
149
|
+
group: describeSource(s),
|
|
150
|
+
hint: s.isSymlink ? "(symlink)" : void 0
|
|
151
|
+
}));
|
|
152
|
+
const picked = await promptMultiselect({ title: "Select Skills to push to the main app", items });
|
|
153
|
+
return picked.map(skillToItem);
|
|
154
|
+
}
|
|
155
|
+
async function selectMcps(includeSecrets) {
|
|
156
|
+
const all = scanMcps();
|
|
157
|
+
if (all.length === 0) {
|
|
158
|
+
process.stderr.write("No MCPs found (scanned current workspace .mcp.json / .claude/.claude.json and global ~/.claude.json)\n");
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
all.sort((a, b) => {
|
|
162
|
+
if (a.source !== b.source) return a.source === "global" ? -1 : 1;
|
|
163
|
+
return a.slug.localeCompare(b.slug);
|
|
164
|
+
});
|
|
165
|
+
const items = all.map((m) => ({
|
|
166
|
+
value: m,
|
|
167
|
+
label: m.slug,
|
|
168
|
+
group: describeSource(m),
|
|
169
|
+
hint: m.hasSecrets && !includeSecrets ? "(env redacted)" : void 0
|
|
170
|
+
}));
|
|
171
|
+
const picked = await promptMultiselect({ title: "Select MCPs to push to the main app", items });
|
|
172
|
+
return picked.map((m) => mcpToItem(m, includeSecrets));
|
|
173
|
+
}
|
|
174
|
+
function renderResults(results) {
|
|
175
|
+
const table = new Table({ head: ["kind", "slug", "status", "message"], wordWrap: true });
|
|
176
|
+
for (const r of results) {
|
|
177
|
+
table.push([r.kind, r.slug, r.status, r.message ?? ""]);
|
|
178
|
+
}
|
|
179
|
+
process.stdout.write(table.toString() + "\n");
|
|
180
|
+
const failed = results.filter((r) => r.status === "failed").length;
|
|
181
|
+
if (failed > 0) {
|
|
182
|
+
process.stderr.write(`
|
|
183
|
+
\u2717 ${failed} item(s) failed
|
|
184
|
+
`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function selectPullResources(args) {
|
|
188
|
+
const all = args.candidates.filter((candidate) => candidate.selected).sort((a, b) => {
|
|
189
|
+
const scopeOrder = {
|
|
190
|
+
system: 0,
|
|
191
|
+
company: 1,
|
|
192
|
+
personal: 2
|
|
193
|
+
};
|
|
194
|
+
const scopeDiff = scopeOrder[a.scope] - scopeOrder[b.scope];
|
|
195
|
+
return scopeDiff !== 0 ? scopeDiff : a.name.localeCompare(b.name);
|
|
196
|
+
});
|
|
197
|
+
if (all.length === 0) {
|
|
198
|
+
process.stderr.write(`${args.title}: no candidates available to sync
|
|
199
|
+
`);
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
const items = all.map((candidate) => ({
|
|
203
|
+
value: candidate,
|
|
204
|
+
label: `${candidate.name} ${candidate.scope}`,
|
|
205
|
+
preselected: true
|
|
206
|
+
}));
|
|
207
|
+
return promptMultiselect({ title: args.title, items });
|
|
208
|
+
}
|
|
209
|
+
function toHttpItems(items) {
|
|
210
|
+
return items.map((item) => {
|
|
211
|
+
if (item.kind === "skill") {
|
|
212
|
+
const { kind: _kind2, dirPath: _dirPath, ...rest2 } = item;
|
|
213
|
+
return rest2;
|
|
214
|
+
}
|
|
215
|
+
const { kind: _kind, ...rest } = item;
|
|
216
|
+
return rest;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
async function pushItems(kind, items) {
|
|
220
|
+
if (items.length === 0) return { results: [] };
|
|
221
|
+
try {
|
|
222
|
+
const resp = await postToMainApp("/api/sandbox/sync/push", {
|
|
223
|
+
kind,
|
|
224
|
+
items: toHttpItems(items)
|
|
225
|
+
});
|
|
226
|
+
return { skillTargetRoot: resp.skillTargetRoot, results: resp.results ?? [] };
|
|
227
|
+
} catch (err) {
|
|
228
|
+
if (err instanceof TeAgentApiError) {
|
|
229
|
+
return {
|
|
230
|
+
results: items.map((it) => ({
|
|
231
|
+
kind: it.kind,
|
|
232
|
+
slug: it.slug,
|
|
233
|
+
status: "failed",
|
|
234
|
+
message: `${err.code ?? err.status} ${err.message}`
|
|
235
|
+
}))
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function copySyncedSkillPackages(skillItems, resp) {
|
|
242
|
+
if (skillItems.length === 0) return;
|
|
243
|
+
const bySlug = new Map(skillItems.map((item) => [item.slug, item]));
|
|
244
|
+
for (const result of resp.results) {
|
|
245
|
+
if (result.kind !== "skill" || result.status !== "synced") continue;
|
|
246
|
+
const item = bySlug.get(result.slug);
|
|
247
|
+
if (!item) continue;
|
|
248
|
+
if (!resp.skillTargetRoot) {
|
|
249
|
+
result.status = "failed";
|
|
250
|
+
result.message = "Main app response is missing skillTargetRoot; cannot copy Skill package";
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
const copied = copySkillPackageToTarget({
|
|
255
|
+
sourceDir: item.dirPath,
|
|
256
|
+
targetRoot: resp.skillTargetRoot,
|
|
257
|
+
slug: item.slug
|
|
258
|
+
});
|
|
259
|
+
updateSkillManifestForSource(item.dirPath, item.slug);
|
|
260
|
+
if (copied.skipped) {
|
|
261
|
+
result.message = "Source directory is already the target directory; local copy skipped";
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
result.status = "failed";
|
|
265
|
+
result.message = `Local copy failed: ${err?.message ?? String(err)}`;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function selectDirection(optsDirection) {
|
|
270
|
+
if (optsDirection === "push" || optsDirection === "pull") return optsDirection;
|
|
271
|
+
if (optsDirection) {
|
|
272
|
+
throw new Error("--direction must be push or pull");
|
|
273
|
+
}
|
|
274
|
+
return promptSingleSelect({
|
|
275
|
+
title: "Sync direction?",
|
|
276
|
+
items: [
|
|
277
|
+
{ value: "push", label: "Workspace -> Main app" },
|
|
278
|
+
{ value: "pull", label: "Main app -> Workspace" }
|
|
279
|
+
]
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
async function selectKind(optsKind) {
|
|
283
|
+
if (optsKind === "skill" || optsKind === "mcp" || optsKind === "both") return optsKind;
|
|
284
|
+
if (optsKind) {
|
|
285
|
+
throw new Error("--kind must be skill, mcp, or both");
|
|
286
|
+
}
|
|
287
|
+
return promptSingleSelect({
|
|
288
|
+
title: "Which resource type to sync?",
|
|
289
|
+
items: [
|
|
290
|
+
{ value: "skill", label: "Skills" },
|
|
291
|
+
{ value: "mcp", label: "MCPs" },
|
|
292
|
+
{ value: "both", label: "Skills + MCPs" }
|
|
293
|
+
]
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
async function runPush(kind, includeSecrets) {
|
|
297
|
+
const skillItems = kind !== "mcp" ? await selectSkills() : [];
|
|
298
|
+
const mcpItems = kind !== "skill" ? await selectMcps(includeSecrets) : [];
|
|
299
|
+
if (skillItems.length === 0 && mcpItems.length === 0) {
|
|
300
|
+
process.stderr.write("Nothing selected, exiting\n");
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
process.stderr.write(`Pushing ${skillItems.length} Skill(s) / ${mcpItems.length} MCP(s) ...
|
|
304
|
+
`);
|
|
305
|
+
const allResults = [];
|
|
306
|
+
if (skillItems.length > 0) {
|
|
307
|
+
const skillResp = await pushItems("skill", skillItems);
|
|
308
|
+
copySyncedSkillPackages(skillItems, skillResp);
|
|
309
|
+
allResults.push(...skillResp.results);
|
|
310
|
+
}
|
|
311
|
+
if (mcpItems.length > 0) {
|
|
312
|
+
const mcpResp = await pushItems("mcp", mcpItems);
|
|
313
|
+
allResults.push(...mcpResp.results);
|
|
314
|
+
}
|
|
315
|
+
renderResults(allResults);
|
|
316
|
+
}
|
|
317
|
+
function pullResultRows(resp) {
|
|
318
|
+
return (resp.results ?? []).map((result) => ({
|
|
319
|
+
kind: result.kind,
|
|
320
|
+
slug: result.name,
|
|
321
|
+
status: result.status,
|
|
322
|
+
message: result.message
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
async function runPull(kind) {
|
|
326
|
+
const workspace = getCurrentWorkspace();
|
|
327
|
+
if (!workspace) {
|
|
328
|
+
throw new Error("Current workspace not recognized; please run from within /home/ta/workspaces/<workspace>");
|
|
329
|
+
}
|
|
330
|
+
const candidates = await getSandboxSyncPullCandidates({
|
|
331
|
+
workspacePath: workspace.name,
|
|
332
|
+
kind
|
|
333
|
+
});
|
|
334
|
+
const skillItems = kind !== "mcp" ? await selectPullResources({
|
|
335
|
+
title: "Select Skills to sync to workspace",
|
|
336
|
+
candidates: candidates.skills ?? []
|
|
337
|
+
}) : [];
|
|
338
|
+
const mcpItems = kind !== "skill" ? await selectPullResources({
|
|
339
|
+
title: "Select MCPs to sync to workspace",
|
|
340
|
+
candidates: candidates.mcp ?? []
|
|
341
|
+
}) : [];
|
|
342
|
+
if (skillItems.length === 0 && mcpItems.length === 0) {
|
|
343
|
+
process.stderr.write("Nothing selected, exiting\n");
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
process.stderr.write(`Syncing to workspace: ${skillItems.length} Skill(s) / ${mcpItems.length} MCP(s) ...
|
|
347
|
+
`);
|
|
348
|
+
const resp = await postSandboxSyncPull({
|
|
349
|
+
workspacePath: workspace.name,
|
|
350
|
+
kind,
|
|
351
|
+
skills: skillItems.map((item) => item.id),
|
|
352
|
+
mcp: mcpItems.map((item) => item.id),
|
|
353
|
+
ifUnmodifiedSince: candidates.mtime
|
|
354
|
+
});
|
|
355
|
+
renderResults(pullResultRows(resp));
|
|
356
|
+
}
|
|
357
|
+
function registerSync(program) {
|
|
358
|
+
program.command("sync").description("Sync Skills / MCPs between current workspace and te-claude main app").option("--direction <direction>", "push | pull (skip interactive direction picker)").option("--include-secrets", "Include MCP env secrets (TOKEN/SECRET/KEY) in push", false).option("--kind <kind>", "skill | mcp | both (skip interactive picker)").action(async (opts) => {
|
|
359
|
+
try {
|
|
360
|
+
const direction = await selectDirection(opts.direction);
|
|
361
|
+
const kind = await selectKind(opts.kind);
|
|
362
|
+
if (direction === "push") await runPush(kind, !!opts.includeSecrets);
|
|
363
|
+
else await runPull(kind);
|
|
364
|
+
} catch (err) {
|
|
365
|
+
if (err instanceof MultiselectCancelled) {
|
|
366
|
+
process.stderr.write("Cancelled\n");
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (err instanceof TeAgentCredentialsError) {
|
|
370
|
+
printError("config", err.message, err.hint);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
if (err instanceof TeAgentApiError) {
|
|
374
|
+
printError("api", err.message, err.code);
|
|
375
|
+
process.exit(1);
|
|
376
|
+
}
|
|
377
|
+
const e = err;
|
|
378
|
+
printError("api", e?.message ?? String(err));
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
export {
|
|
384
|
+
registerSync
|
|
385
|
+
};
|