@thinkingai/ae-cli 6.1.14 → 6.1.16

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.
Files changed (89) hide show
  1. package/dist/{auth-GBMV6TEJ.js → auth-2WTQOP77.js} +3 -3
  2. package/dist/{auth-NDSXE54J.js → auth-77BUFLGC.js} +57 -13
  3. package/dist/{capability-TAMDRZYV.js → capability-72DTW5M2.js} +9 -9
  4. package/dist/{capability-U7TDEEEG.js → capability-PJHNI4GJ.js} +9 -9
  5. package/dist/{chunk-AFXA7BRK.js → chunk-4KVPKXFX.js} +5 -5
  6. package/dist/chunk-4SGZG4XY.js +311 -0
  7. package/dist/chunk-6EIJSNBD.js +8 -0
  8. package/dist/chunk-C4MGVGJW.js +13 -0
  9. package/dist/{chunk-WZRX4KOH.js → chunk-GT46FPXN.js} +4 -6
  10. package/dist/{chunk-5XUSIK27.js → chunk-ILIU36SU.js} +10 -7
  11. package/dist/{chunk-JHENBQ5B.js → chunk-LYVNONC4.js} +0 -35
  12. package/dist/{chunk-JUW4AJXN.js → chunk-P3FGXJTU.js} +12 -7
  13. package/dist/chunk-QGM4M3NI.js +37 -0
  14. package/dist/{chunk-753BUTNZ.js → chunk-RGKJGKT7.js} +2 -2
  15. package/dist/{chunk-UIHQJK5E.js → chunk-SAU3QFIQ.js} +3 -3
  16. package/dist/{chunk-VLWOLBGZ.js → chunk-UOUS37JQ.js} +149 -161
  17. package/dist/{chunk-AXDXJTPC.js → chunk-UW5UN47B.js} +19 -2
  18. package/dist/chunk-VPKZ7I72.js +509 -0
  19. package/dist/{chunk-QATA32VR.js → chunk-VR3LCBHW.js} +2 -2
  20. package/dist/{chunk-IBH3LDAH.js → chunk-YA6SMTXG.js} +3 -3
  21. package/dist/chunk-ZZUOD757.js +598 -0
  22. package/dist/{client-L2YDMHQ6.js → client-TKG4WBHN.js} +4 -5
  23. package/dist/{community-report-client-M2RW4MXD.js → community-report-client-FI4LNVYS.js} +3 -2
  24. package/dist/{config-OL2LWGBV.js → config-RE6CMGPK.js} +7 -7
  25. package/dist/data-integration-2MYMANJI.js +3383 -0
  26. package/dist/index.js +68 -34
  27. package/dist/local-data-upload-client-BWHSUQQK.js +167 -0
  28. package/dist/{memory-MUP7PPL7.js → memory-CHRU2F7W.js} +7 -6
  29. package/dist/{memory-U4O5PMXH.js → memory-YK33G4T7.js} +7 -6
  30. package/dist/{metadata-5MIMNIMT.js → metadata-UILXHBWF.js} +10 -9
  31. package/dist/{metadata-LERKDJN6.js → metadata-XXR34N5P.js} +10 -9
  32. package/dist/{model-JTUEO5M4.js → model-K3KLWIW6.js} +7 -3
  33. package/dist/model-NR3JHFSJ.js +139 -0
  34. package/dist/{sync-MOSFNBVR.js → sync-DAVKYVMW.js} +8 -6
  35. package/dist/sync-FCKOVWWS.js +10261 -0
  36. package/dist/{te-agent-IFKZDHZI.js → te-agent-4BKBODMF.js} +686 -71
  37. package/dist/te-agent-HLW4VTQK.js +3893 -0
  38. package/dist/{te-analysis-FCHRTNIY.js → te-analysis-O6DCO6BS.js} +36 -13
  39. package/dist/{te-analysis-QG7UKGDA.js → te-analysis-ZMNGOVNW.js} +36 -13
  40. package/dist/{te-community-HNKVTERD.js → te-community-6HPBWJUZ.js} +24 -19
  41. package/dist/{te-community-IWE5B7W6.js → te-community-HLC43QKH.js} +24 -20
  42. package/dist/{te-dataops-KXCEB4CS.js → te-dataops-EJP56W3K.js} +57 -34
  43. package/dist/{te-dataops-KQPYNAE3.js → te-dataops-HDRUXY4K.js} +59 -34
  44. package/dist/{te-engage-D6EG3NOR.js → te-engage-FGBGQ4IY.js} +9 -8
  45. package/dist/{te-engage-ZSMIJLUW.js → te-engage-RAK5PESW.js} +9 -8
  46. package/dist/{te-experiment-K5US7RMG.js → te-experiment-SO5MPDMJ.js} +9 -8
  47. package/dist/{te-experiment-WA7TFMEL.js → te-experiment-VZF7BT6G.js} +9 -8
  48. package/dist/{te-kb-OIH3T6CS.js → te-kb-APXBWBDY.js} +6 -6
  49. package/dist/{te-system-AZ3URMUO.js → te-system-YARIK4S5.js} +7 -4
  50. package/dist/te-system-Z77IKZFN.js +2213 -0
  51. package/dist/{te-team-GZPU6UWA.js → te-team-EFKWYKMK.js} +7 -7
  52. package/dist/{update-TOBFXF2V.js → update-OGPSZM5A.js} +7 -7
  53. package/package.json +13 -3
  54. package/skills/ae-agent/SKILL.md +21 -11
  55. package/skills/ae-agent/references/approval-effect.md +44 -0
  56. package/skills/ae-agent/references/approval-request.md +46 -0
  57. package/skills/ae-agent/references/approval-task.md +45 -0
  58. package/skills/ae-agent/references/approval-type.md +32 -0
  59. package/skills/ae-agent/references/command_index.md +19 -0
  60. package/skills/ae-analysis/SKILL.md +11 -7
  61. package/skills/ae-analysis/references/adhoc_run.md +2 -0
  62. package/skills/ae-analysis/references/ai_models.md +27 -0
  63. package/skills/ae-analysis/references/analysis_gateway_assets.md +3 -2
  64. package/skills/ae-analysis/references/command_index.md +4 -1
  65. package/skills/ae-analysis/references/dashboard_get.md +8 -2
  66. package/skills/ae-analysis/references/dashboard_report_data_run.md +3 -1
  67. package/skills/ae-analysis/references/dashboard_update.md +4 -1
  68. package/skills/ae-analysis/references/project_space_business_filter_upsert.md +17 -0
  69. package/skills/ae-analysis/references/user_tag_models.md +4 -4
  70. package/skills/ae-data-integration/SKILL.md +54 -0
  71. package/skills/ae-data-integration/references/handoff.md +43 -0
  72. package/skills/ae-data-integration/references/local-analysis.md +27 -0
  73. package/skills/ae-data-integration/references/reuse.md +41 -0
  74. package/skills/ae-data-integration/references/sink-upload.md +58 -0
  75. package/skills/ae-data-integration/references/source-inspect.md +55 -0
  76. package/skills/ae-data-integration/references/sync-json-upload.md +60 -0
  77. package/skills/ae-data-integration/references/tracking-plan.md +35 -0
  78. package/skills/ae-data-integration/references/transform.md +65 -0
  79. package/skills/ae-data-integration/references/ue-mapping.md +142 -0
  80. package/skills/ae-data-integration/references/ue-routing.md +35 -0
  81. package/skills/ae-data-integration-helper/SKILL.md +1 -1
  82. package/skills/ae-dataops/SKILL.md +1 -1
  83. package/skills/ae-dataops/references/dataops-query.md +4 -4
  84. package/skills/ae-generate-tracking-plan/SKILL.md +54 -3
  85. package/skills/ae-metadata/SKILL.md +0 -1
  86. package/dist/chunk-3FY3RJ26.js +0 -293
  87. package/dist/chunk-S5NTSDBS.js +0 -198
  88. package/dist/chunk-ZQKDZXDO.js +0 -317
  89. package/dist/cli-token-4UPER74P.js +0 -21
@@ -0,0 +1,3893 @@
1
+ import {
2
+ assertValidSkillVersion
3
+ } from "./chunk-4NN5IWVN.js";
4
+ import {
5
+ deleteFromMainApp,
6
+ getBufferFromMainApp,
7
+ getFromMainApp,
8
+ patchToMainApp,
9
+ postToMainApp,
10
+ putToMainApp,
11
+ uploadToMainApp
12
+ } from "./chunk-UOUS37JQ.js";
13
+ import {
14
+ buildCapabilityGatewayUrl,
15
+ callCapabilityApi
16
+ } from "./chunk-P3FGXJTU.js";
17
+ import "./chunk-C4MGVGJW.js";
18
+ import "./chunk-4SGZG4XY.js";
19
+ import "./chunk-ZZUOD757.js";
20
+ import {
21
+ CliValidationError
22
+ } from "./chunk-UW5UN47B.js";
23
+ import "./chunk-LYVNONC4.js";
24
+ import "./chunk-QGM4M3NI.js";
25
+
26
+ // src/commands/te-agent/api-client.ts
27
+ function getAgentApi(ctx, path) {
28
+ return getFromMainApp(path, ctx.host());
29
+ }
30
+ function postAgentApi(ctx, path, body) {
31
+ return postToMainApp(path, body, ctx.host());
32
+ }
33
+ function patchAgentApi(ctx, path, body) {
34
+ return patchToMainApp(path, body, ctx.host());
35
+ }
36
+ function putAgentApi(ctx, path, body) {
37
+ return putToMainApp(path, body, ctx.host());
38
+ }
39
+ function deleteAgentApi(ctx, path) {
40
+ return deleteFromMainApp(path, ctx.host());
41
+ }
42
+ function uploadAgentApi(ctx, path, formData) {
43
+ return uploadToMainApp(path, formData, ctx.host());
44
+ }
45
+ function getAgentBuffer(ctx, path) {
46
+ return getBufferFromMainApp(path, ctx.host());
47
+ }
48
+
49
+ // src/commands/te-agent/agents.ts
50
+ var BASE_PATH = "/api/sandbox/agent/agents";
51
+ function buildQuery(ctx) {
52
+ const params = new URLSearchParams();
53
+ const scope = ctx.str("scope");
54
+ const q = ctx.str("q");
55
+ if (scope) params.set("scope", scope);
56
+ if (q) params.set("q", q);
57
+ const qs = params.toString();
58
+ return qs ? `?${qs}` : "";
59
+ }
60
+ var listAgents = {
61
+ service: "agent",
62
+ command: "+list-agents",
63
+ description: "List Agents visible to current user",
64
+ flags: [
65
+ {
66
+ name: "scope",
67
+ type: "string",
68
+ required: false,
69
+ desc: "Filter by scope: personal | company | system"
70
+ },
71
+ {
72
+ name: "q",
73
+ type: "string",
74
+ required: false,
75
+ desc: "Search by Agent name or description"
76
+ }
77
+ ],
78
+ risk: "read",
79
+ validate: (ctx) => {
80
+ const scope = ctx.str("scope");
81
+ if (scope && !["personal", "company", "system"].includes(scope)) {
82
+ throw new Error("--scope \u5FC5\u987B\u662F personal\u3001company \u6216 system");
83
+ }
84
+ },
85
+ dryRun: (ctx) => ({ method: "GET", url: `${BASE_PATH}${buildQuery(ctx)}` }),
86
+ execute: async (ctx) => getAgentApi(ctx, `${BASE_PATH}${buildQuery(ctx)}`)
87
+ };
88
+ async function resolveInstructions(raw) {
89
+ if (raw === "@-") {
90
+ const chunks = [];
91
+ for await (const chunk of process.stdin) {
92
+ chunks.push(chunk);
93
+ }
94
+ const text = Buffer.concat(chunks).toString("utf8").trim();
95
+ if (!text) throw new Error("stdin is empty; cannot read instructions");
96
+ return text;
97
+ }
98
+ return raw;
99
+ }
100
+ var createAgent = {
101
+ service: "agent",
102
+ command: "+create-agent",
103
+ description: "Create an Agent (personal scope by default; company requires root/agent_admin)",
104
+ flags: [
105
+ { name: "name", type: "string", required: true, desc: "Agent name (1-100 chars)" },
106
+ { name: "description", type: "string", required: false, desc: "Agent description (max 2000 chars)" },
107
+ { name: "instructions", type: "string", required: false, desc: "Agent system prompt (use @- to read from stdin)" },
108
+ { name: "scope", type: "string", required: false, default: "personal", desc: "Scope: personal | company (company requires root/agent_admin)" },
109
+ { name: "model-id", type: "string", required: false, desc: "Model identifier (Model.id uuid or legacy modelId); omit to use global default" },
110
+ { name: "mcp-ids", type: "json", required: false, desc: 'MCP server record IDs as JSON array string (e.g. ["id1","id2"])' },
111
+ { name: "skill-ids", type: "json", required: false, desc: "Skill record IDs as JSON array string" },
112
+ { name: "auto-rename", type: "boolean", required: false, desc: "Auto-rename on name conflict (append -N suffix)" }
113
+ ],
114
+ risk: "write",
115
+ validate: (ctx) => {
116
+ const name = ctx.str("name");
117
+ if (!name || name.length < 1 || name.length > 100) {
118
+ throw new Error("--name length must be between 1 and 100");
119
+ }
120
+ const scope = ctx.str("scope");
121
+ if (scope && !["personal", "company"].includes(scope)) {
122
+ throw new Error("--scope must be personal or company");
123
+ }
124
+ },
125
+ dryRun: (ctx) => {
126
+ const body = {
127
+ name: ctx.str("name"),
128
+ scope: ctx.str("scope") || "personal"
129
+ };
130
+ const description = ctx.str("description");
131
+ if (description) body.description = description;
132
+ const instructions = ctx.str("instructions");
133
+ if (instructions) body.systemPrompt = instructions === "@-" ? "(from stdin)" : instructions;
134
+ const modelId = ctx.str("modelId");
135
+ if (modelId) body.model = modelId;
136
+ const mcpIds = ctx.json("mcpIds");
137
+ if (mcpIds) body.mcpServerIds = mcpIds;
138
+ const skillIds = ctx.json("skillIds");
139
+ if (skillIds) body.skillIds = skillIds;
140
+ if (ctx.bool("autoRename")) body.autoRename = true;
141
+ return { method: "POST", url: BASE_PATH, body };
142
+ },
143
+ execute: async (ctx) => {
144
+ const body = {
145
+ name: ctx.str("name"),
146
+ scope: ctx.str("scope") || "personal"
147
+ };
148
+ const description = ctx.str("description");
149
+ if (description) body.description = description;
150
+ const instructionsRaw = ctx.str("instructions");
151
+ if (instructionsRaw) body.systemPrompt = await resolveInstructions(instructionsRaw);
152
+ const modelId = ctx.str("modelId");
153
+ if (modelId) body.model = modelId;
154
+ const mcpIds = ctx.json("mcpIds");
155
+ if (mcpIds) body.mcpServerIds = mcpIds;
156
+ const skillIds = ctx.json("skillIds");
157
+ if (skillIds) body.skillIds = skillIds;
158
+ if (ctx.bool("autoRename")) body.autoRename = true;
159
+ return postAgentApi(ctx, BASE_PATH, body);
160
+ }
161
+ };
162
+ var updateAgent = {
163
+ service: "agent",
164
+ command: "+update-agent",
165
+ description: "Update an Agent (name/description/instructions/model/MCP/Skill/enabled)",
166
+ flags: [
167
+ { name: "id", type: "string", required: true, desc: "Agent record ID (CUID)" },
168
+ { name: "name", type: "string", required: false, desc: "New Agent name (1-100 chars)" },
169
+ { name: "description", type: "string", required: false, desc: "New description (max 2000 chars)" },
170
+ { name: "instructions", type: "string", required: false, desc: "New system prompt (use @- to read from stdin)" },
171
+ { name: "model-id", type: "string", required: false, desc: "New model identifier (uuid or legacy modelId); omit to keep" },
172
+ { name: "mcp-ids", type: "json", required: false, desc: "MCP server record IDs as JSON array string (replaces the list; [] clears)" },
173
+ { name: "skill-ids", type: "json", required: false, desc: "Skill record IDs as JSON array string (replaces the list; [] clears)" },
174
+ { name: "enabled", type: "boolean", required: false, desc: "Enable/disable (system/company: writes personal preference)" }
175
+ ],
176
+ risk: "write",
177
+ validate: (ctx) => {
178
+ const name = ctx.str("name");
179
+ if (name && (name.length < 1 || name.length > 100)) {
180
+ throw new Error("--name length must be between 1 and 100");
181
+ }
182
+ },
183
+ dryRun: (ctx) => {
184
+ const body = {};
185
+ const name = ctx.str("name");
186
+ if (name) body.name = name;
187
+ const description = ctx.str("description");
188
+ if (description) body.description = description;
189
+ const instructions = ctx.str("instructions");
190
+ if (instructions) body.systemPrompt = instructions === "@-" ? "(from stdin)" : instructions;
191
+ const modelId = ctx.str("modelId");
192
+ if (modelId) body.model = modelId;
193
+ const mcpIds = ctx.json("mcpIds");
194
+ if (mcpIds) body.mcpServerIds = mcpIds;
195
+ const skillIds = ctx.json("skillIds");
196
+ if (skillIds) body.skillIds = skillIds;
197
+ if (ctx.str("enabled")) body.enabled = ctx.bool("enabled");
198
+ return { method: "PATCH", url: `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`, body };
199
+ },
200
+ execute: async (ctx) => {
201
+ const body = {};
202
+ const name = ctx.str("name");
203
+ if (name) body.name = name;
204
+ const description = ctx.str("description");
205
+ if (description) body.description = description;
206
+ const instructionsRaw = ctx.str("instructions");
207
+ if (instructionsRaw) body.systemPrompt = await resolveInstructions(instructionsRaw);
208
+ const modelId = ctx.str("modelId");
209
+ if (modelId) body.model = modelId;
210
+ const mcpIds = ctx.json("mcpIds");
211
+ if (mcpIds) body.mcpServerIds = mcpIds;
212
+ const skillIds = ctx.json("skillIds");
213
+ if (skillIds) body.skillIds = skillIds;
214
+ if (ctx.str("enabled")) body.enabled = ctx.bool("enabled");
215
+ return patchAgentApi(ctx, `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`, body);
216
+ }
217
+ };
218
+ var delAgent = {
219
+ service: "agent",
220
+ command: "+del-agent",
221
+ description: "Soft-delete an Agent (system agents cannot be deleted)",
222
+ flags: [
223
+ { name: "id", type: "string", required: true, desc: "Agent record ID (CUID)" }
224
+ ],
225
+ risk: "high-risk-write",
226
+ dryRun: (ctx) => ({
227
+ method: "DELETE",
228
+ url: `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`
229
+ }),
230
+ execute: async (ctx) => {
231
+ return deleteAgentApi(ctx, `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`);
232
+ }
233
+ };
234
+ var getAgent = {
235
+ service: "agent",
236
+ command: "+get-agent",
237
+ description: "Get Agent details by ID",
238
+ flags: [
239
+ { name: "id", type: "string", required: true, desc: "Agent record ID (CUID)" }
240
+ ],
241
+ risk: "read",
242
+ dryRun: (ctx) => ({
243
+ method: "GET",
244
+ url: `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`
245
+ }),
246
+ execute: async (ctx) => {
247
+ return getAgentApi(ctx, `${BASE_PATH}/${encodeURIComponent(ctx.str("id"))}`);
248
+ }
249
+ };
250
+
251
+ // src/commands/te-agent/models.ts
252
+ var BASE_PATH2 = "/api/sandbox/agent/models";
253
+ var listModels = {
254
+ service: "agent",
255
+ command: "+list-models",
256
+ description: "List models visible to current user (personal / company / system)",
257
+ flags: [
258
+ {
259
+ name: "scope",
260
+ type: "string",
261
+ required: false,
262
+ desc: "Filter by scope: personal | company | system"
263
+ }
264
+ ],
265
+ risk: "read",
266
+ validate: (ctx) => {
267
+ const scope = ctx.str("scope");
268
+ if (scope && !["personal", "company", "system"].includes(scope)) {
269
+ throw new Error("--scope must be personal, company, or system");
270
+ }
271
+ },
272
+ dryRun: (ctx) => {
273
+ const scope = ctx.str("scope");
274
+ const params = new URLSearchParams();
275
+ if (scope) params.set("scope", scope);
276
+ const qs = params.toString();
277
+ return { method: "GET", url: `${BASE_PATH2}${qs ? `?${qs}` : ""}` };
278
+ },
279
+ execute: async (ctx) => {
280
+ const scope = ctx.str("scope");
281
+ const params = new URLSearchParams();
282
+ if (scope) params.set("scope", scope);
283
+ const qs = params.toString();
284
+ const current = process.env.TE_AGENT_CURRENT_MODEL_ID?.trim();
285
+ const data = await getAgentApi(
286
+ ctx,
287
+ `${BASE_PATH2}${qs ? `?${qs}` : ""}`
288
+ );
289
+ const items = data?.items ?? [];
290
+ return {
291
+ models: items.map((m) => ({
292
+ ...m,
293
+ isCurrent: current ? m.id === current : false
294
+ }))
295
+ };
296
+ }
297
+ };
298
+ var addModel = {
299
+ service: "agent",
300
+ command: "+add-model",
301
+ description: "Add a custom model (personal or company scope)",
302
+ flags: [
303
+ {
304
+ name: "model-id",
305
+ type: "string",
306
+ required: true,
307
+ desc: "Model identifier (e.g. gpt-4o)"
308
+ },
309
+ { name: "name", type: "string", required: true, desc: "Display name" },
310
+ { name: "base-url", type: "string", required: true, desc: "API base URL" },
311
+ { name: "api-key", type: "string", required: false, desc: "API key" },
312
+ {
313
+ name: "provider",
314
+ type: "string",
315
+ required: false,
316
+ desc: "Provider name"
317
+ },
318
+ {
319
+ name: "description",
320
+ type: "string",
321
+ required: false,
322
+ desc: "Description"
323
+ },
324
+ {
325
+ name: "context-length",
326
+ type: "number",
327
+ required: false,
328
+ desc: "Context window length"
329
+ },
330
+ {
331
+ name: "scope",
332
+ type: "string",
333
+ required: false,
334
+ default: "personal",
335
+ desc: "Target scope: personal | company"
336
+ }
337
+ ],
338
+ risk: "write",
339
+ validate: (ctx) => {
340
+ const baseUrl = ctx.str("baseUrl");
341
+ try {
342
+ new URL(baseUrl);
343
+ } catch {
344
+ throw new Error("--base-url must be a valid URL");
345
+ }
346
+ const scope = ctx.str("scope");
347
+ if (scope && !["personal", "company"].includes(scope)) {
348
+ throw new Error("--scope must be personal or company");
349
+ }
350
+ },
351
+ dryRun: (ctx) => ({
352
+ method: "POST",
353
+ url: BASE_PATH2,
354
+ body: {
355
+ modelId: ctx.str("modelId"),
356
+ displayName: ctx.str("name"),
357
+ baseUrl: ctx.str("baseUrl"),
358
+ apiKey: ctx.str("apiKey") || void 0,
359
+ provider: ctx.str("provider") || void 0,
360
+ description: ctx.str("description") || void 0,
361
+ contextLength: ctx.num("contextLength") || void 0,
362
+ scope: ctx.str("scope") || "personal"
363
+ }
364
+ }),
365
+ execute: async (ctx) => {
366
+ return postAgentApi(ctx, BASE_PATH2, {
367
+ modelId: ctx.str("modelId"),
368
+ displayName: ctx.str("name"),
369
+ baseUrl: ctx.str("baseUrl"),
370
+ apiKey: ctx.str("apiKey") || void 0,
371
+ provider: ctx.str("provider") || void 0,
372
+ description: ctx.str("description") || void 0,
373
+ contextLength: ctx.num("contextLength") || void 0,
374
+ scope: ctx.str("scope") || "personal"
375
+ });
376
+ }
377
+ };
378
+ var delModel = {
379
+ service: "agent",
380
+ command: "+del-model",
381
+ description: "Delete a model (personal or company scope)",
382
+ flags: [
383
+ {
384
+ name: "id",
385
+ type: "string",
386
+ required: true,
387
+ desc: "Model record ID (CUID)"
388
+ },
389
+ {
390
+ name: "scope",
391
+ type: "string",
392
+ required: false,
393
+ default: "personal",
394
+ desc: "Target scope: personal | company"
395
+ }
396
+ ],
397
+ risk: "high-risk-write",
398
+ validate: (ctx) => {
399
+ const scope = ctx.str("scope");
400
+ if (scope && !["personal", "company"].includes(scope)) {
401
+ throw new Error("--scope must be personal or company");
402
+ }
403
+ },
404
+ dryRun: (ctx) => {
405
+ const scope = ctx.str("scope") || "personal";
406
+ const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(scope)}`;
407
+ return { method: "DELETE", url: `${BASE_PATH2}?${qs}` };
408
+ },
409
+ execute: async (ctx) => {
410
+ const scope = ctx.str("scope") || "personal";
411
+ const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(scope)}`;
412
+ return deleteAgentApi(ctx, `${BASE_PATH2}?${qs}`);
413
+ }
414
+ };
415
+ var toggleModel = {
416
+ service: "agent",
417
+ command: "+toggle-model",
418
+ description: "Enable or disable a model",
419
+ flags: [
420
+ {
421
+ name: "id",
422
+ type: "string",
423
+ required: true,
424
+ desc: "Model record ID (CUID)"
425
+ },
426
+ {
427
+ name: "enabled",
428
+ type: "boolean",
429
+ required: true,
430
+ desc: "true to enable, false to disable"
431
+ }
432
+ ],
433
+ risk: "write",
434
+ dryRun: (ctx) => ({
435
+ method: "PATCH",
436
+ url: BASE_PATH2,
437
+ body: { id: ctx.str("id"), enabled: ctx.bool("enabled") }
438
+ }),
439
+ execute: async (ctx) => {
440
+ return patchAgentApi(ctx, BASE_PATH2, {
441
+ id: ctx.str("id"),
442
+ enabled: ctx.bool("enabled")
443
+ });
444
+ }
445
+ };
446
+ var updateModel = {
447
+ service: "agent",
448
+ command: "+update-model",
449
+ description: "Update a custom model (id determines the record to update; personal or company scope)",
450
+ flags: [
451
+ { name: "id", type: "string", required: true, desc: "Model record ID (CUID) to update" },
452
+ { name: "model-id", type: "string", required: true, desc: "Model identifier (e.g. gpt-4o)" },
453
+ { name: "name", type: "string", required: true, desc: "Display name" },
454
+ { name: "base-url", type: "string", required: true, desc: "API base URL (must be a valid URL)" },
455
+ { name: "api-key", type: "string", required: false, desc: "API key; omit or empty to preserve the existing key" },
456
+ { name: "provider", type: "string", required: false, desc: "Provider name" },
457
+ { name: "description", type: "string", required: false, desc: "Description" },
458
+ { name: "context-length", type: "number", required: false, desc: "Context window length" },
459
+ { name: "connectivity-verified", type: "boolean", required: false, desc: "Whether connectivity was verified (default false; pass true after +test-model)" },
460
+ { name: "auto-rename", type: "boolean", required: false, desc: "Auto-rename on display name conflict (append -N suffix)" },
461
+ { name: "scope", type: "string", required: false, default: "personal", desc: "Target scope: personal | company" }
462
+ ],
463
+ risk: "write",
464
+ validate: (ctx) => {
465
+ const baseUrl = ctx.str("baseUrl");
466
+ try {
467
+ new URL(baseUrl);
468
+ } catch {
469
+ throw new Error("--base-url must be a valid URL");
470
+ }
471
+ const scope = ctx.str("scope");
472
+ if (scope && !["personal", "company"].includes(scope)) {
473
+ throw new Error("--scope must be personal or company");
474
+ }
475
+ },
476
+ dryRun: (ctx) => {
477
+ const body = {
478
+ id: ctx.str("id"),
479
+ modelId: ctx.str("modelId"),
480
+ displayName: ctx.str("name"),
481
+ baseUrl: ctx.str("baseUrl"),
482
+ connectivityVerified: ctx.bool("connectivityVerified")
483
+ };
484
+ const apiKey = ctx.str("apiKey");
485
+ if (apiKey) body.apiKey = apiKey;
486
+ const provider = ctx.str("provider");
487
+ if (provider) body.provider = provider;
488
+ const description = ctx.str("description");
489
+ if (description) body.description = description;
490
+ const contextLength = ctx.optionalNum("contextLength");
491
+ if (contextLength !== void 0) body.contextLength = contextLength;
492
+ if (ctx.bool("autoRename")) body.autoRename = true;
493
+ body.scope = ctx.str("scope") || "personal";
494
+ return { method: "POST", url: BASE_PATH2, body };
495
+ },
496
+ execute: async (ctx) => {
497
+ const body = {
498
+ id: ctx.str("id"),
499
+ modelId: ctx.str("modelId"),
500
+ displayName: ctx.str("name"),
501
+ baseUrl: ctx.str("baseUrl"),
502
+ connectivityVerified: ctx.bool("connectivityVerified")
503
+ };
504
+ const apiKey = ctx.str("apiKey");
505
+ if (apiKey) body.apiKey = apiKey;
506
+ const provider = ctx.str("provider");
507
+ if (provider) body.provider = provider;
508
+ const description = ctx.str("description");
509
+ if (description) body.description = description;
510
+ const contextLength = ctx.optionalNum("contextLength");
511
+ if (contextLength !== void 0) body.contextLength = contextLength;
512
+ if (ctx.bool("autoRename")) body.autoRename = true;
513
+ body.scope = ctx.str("scope") || "personal";
514
+ return postAgentApi(ctx, BASE_PATH2, body);
515
+ }
516
+ };
517
+ var testModel = {
518
+ service: "agent",
519
+ command: "+test-model",
520
+ description: "Test model connectivity (LLM models only)",
521
+ flags: [
522
+ { name: "model-id", type: "string", required: true, desc: "Model identifier (e.g. gpt-4o)" },
523
+ { name: "base-url", type: "string", required: true, desc: "API base URL (must be a valid URL)" },
524
+ { name: "api-key", type: "string", required: false, desc: "API key; omit to reuse the stored key of --id" },
525
+ { name: "provider", type: "string", required: false, desc: "Provider name" },
526
+ { name: "id", type: "string", required: false, desc: "Existing model config ID; when --api-key is omitted, the stored key is decrypted and reused" }
527
+ ],
528
+ risk: "read",
529
+ validate: (ctx) => {
530
+ const baseUrl = ctx.str("baseUrl");
531
+ try {
532
+ new URL(baseUrl);
533
+ } catch {
534
+ throw new Error("--base-url must be a valid URL");
535
+ }
536
+ },
537
+ dryRun: (ctx) => {
538
+ const body = {
539
+ modelId: ctx.str("modelId"),
540
+ baseUrl: ctx.str("baseUrl")
541
+ };
542
+ const apiKey = ctx.str("apiKey");
543
+ if (apiKey) body.apiKey = apiKey;
544
+ const provider = ctx.str("provider");
545
+ if (provider) body.provider = provider;
546
+ const id = ctx.str("id");
547
+ if (id) body.existingConfigId = id;
548
+ return { method: "POST", url: `${BASE_PATH2}/test`, body };
549
+ },
550
+ execute: async (ctx) => {
551
+ const body = {
552
+ modelId: ctx.str("modelId"),
553
+ baseUrl: ctx.str("baseUrl")
554
+ };
555
+ const apiKey = ctx.str("apiKey");
556
+ if (apiKey) body.apiKey = apiKey;
557
+ const provider = ctx.str("provider");
558
+ if (provider) body.provider = provider;
559
+ const id = ctx.str("id");
560
+ if (id) body.existingConfigId = id;
561
+ return postAgentApi(ctx, `${BASE_PATH2}/test`, body);
562
+ }
563
+ };
564
+
565
+ // src/commands/te-agent/market-constants.ts
566
+ var MARKET_CATEGORIES = [
567
+ "ae_preset",
568
+ "dev_tool",
569
+ "search_tool",
570
+ "data_query",
571
+ "content_gen",
572
+ "enterprise",
573
+ "life",
574
+ "automation",
575
+ "other"
576
+ ];
577
+ var MARKET_SCOPES = ["all", "system", "company", "custom"];
578
+ var MARKET_SORTS = ["newest", "calls", "likes"];
579
+ var SUBMISSION_STATUSES = ["pending", "approved", "rejected", "cancelled"];
580
+ var SHARE_DIRECTIONS = ["received", "sent"];
581
+ var SHARE_STATUSES = ["pending", "accepted", "rejected"];
582
+ function isValidMarketCategory(key) {
583
+ return !!key && MARKET_CATEGORIES.includes(key);
584
+ }
585
+ function buildMarketQuery(ctx) {
586
+ const params = new URLSearchParams();
587
+ params.set("scope", ctx.str("scope") || "all");
588
+ const category = ctx.str("category");
589
+ if (category) params.set("category", category);
590
+ const search = ctx.str("search");
591
+ if (search) params.set("search", search);
592
+ params.set("sort", ctx.str("sort") || "newest");
593
+ params.set("limit", String(ctx.num("limit") || 50));
594
+ params.set("offset", String(ctx.num("offset") || 0));
595
+ return params;
596
+ }
597
+
598
+ // src/commands/te-agent/mcps.ts
599
+ var BASE_PATH3 = "/api/sandbox/agent/mcp-servers";
600
+ var MARKET_BASE_PATH = "/api/sandbox/agent/mcp-servers";
601
+ var CRED_BASE_PATH = "/api/sandbox/agent/mcp-credentials";
602
+ var STATS_PATH = "/api/sandbox/agent/mcp-servers/stats";
603
+ function buildMetaBody(ctx) {
604
+ const body = {};
605
+ const category = ctx.str("category");
606
+ const iconEmoji = ctx.str("iconEmoji");
607
+ const iconColor = ctx.str("iconColor");
608
+ if (category) body.category = category;
609
+ if (iconEmoji) body.iconEmoji = iconEmoji;
610
+ if (iconColor) body.iconColor = iconColor;
611
+ return Object.keys(body).length > 0 ? body : null;
612
+ }
613
+ var listMcps = {
614
+ service: "agent",
615
+ command: "+list-mcps",
616
+ description: "List MCP servers visible to current user",
617
+ flags: [
618
+ { name: "scope", type: "string", required: false, desc: "Filter by scope: personal | company | system" }
619
+ ],
620
+ risk: "read",
621
+ validate: (ctx) => {
622
+ const scope = ctx.str("scope");
623
+ if (scope && !["personal", "company", "system"].includes(scope)) {
624
+ throw new Error("--scope must be personal, company, or system");
625
+ }
626
+ },
627
+ dryRun: (ctx) => {
628
+ const scope = ctx.str("scope");
629
+ const qs = scope ? `?scope=${encodeURIComponent(scope)}` : "";
630
+ return { method: "GET", url: `${BASE_PATH3}${qs}` };
631
+ },
632
+ execute: async (ctx) => {
633
+ const scope = ctx.str("scope");
634
+ const qs = scope ? `?scope=${encodeURIComponent(scope)}` : "";
635
+ return getAgentApi(ctx, `${BASE_PATH3}${qs}`);
636
+ }
637
+ };
638
+ var addMcp = {
639
+ service: "agent",
640
+ command: "+add-mcp",
641
+ description: "Add an MCP server (personal or company scope)",
642
+ flags: [
643
+ { name: "name", type: "string", required: true, desc: "Server name (2-64 chars, letter start, [a-zA-Z0-9_-])" },
644
+ { name: "url", type: "string", required: true, desc: "MCP server URL" },
645
+ { name: "display-name", type: "string", required: false, desc: "Display name (max 100)" },
646
+ { name: "description", type: "string", required: false, desc: "Description (max 255)" },
647
+ { name: "transport", type: "string", required: false, default: "http", desc: "Transport: sse | http" },
648
+ { name: "headers", type: "json", required: false, desc: "HTTP headers as JSON object" },
649
+ { name: "category", type: "string", required: false, desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}` },
650
+ { name: "icon-emoji", type: "string", required: false, desc: "Market icon emoji (e.g. robot)" },
651
+ { name: "icon-color", type: "string", required: false, desc: "Market icon color (e.g. #1E76F0)" },
652
+ { name: "scope", type: "string", required: false, default: "personal", desc: "Target scope: personal | company" }
653
+ ],
654
+ risk: "write",
655
+ validate: (ctx) => {
656
+ const name = ctx.str("name");
657
+ if (!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
658
+ throw new Error("--name must start with a letter and contain only letters, digits, _, or -");
659
+ }
660
+ if (name.length < 2 || name.length > 64) {
661
+ throw new Error("--name length must be between 2 and 64");
662
+ }
663
+ try {
664
+ new URL(ctx.str("url"));
665
+ } catch {
666
+ throw new Error("--url must be a valid URL");
667
+ }
668
+ if (!/^https?:\/\//i.test(ctx.str("url"))) {
669
+ throw new Error("--url only supports http:// or https:// protocols");
670
+ }
671
+ const transport = ctx.str("transport");
672
+ if (transport && !["sse", "http"].includes(transport)) {
673
+ throw new Error("--transport must be sse or http");
674
+ }
675
+ const category = ctx.str("category");
676
+ if (category && !isValidMarketCategory(category)) {
677
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
678
+ }
679
+ const scope = ctx.str("scope");
680
+ if (scope && !["personal", "company"].includes(scope)) {
681
+ throw new Error("--scope must be personal or company");
682
+ }
683
+ },
684
+ dryRun: (ctx) => {
685
+ const body = {
686
+ name: ctx.str("name"),
687
+ url: ctx.str("url"),
688
+ displayName: ctx.str("displayName") || void 0,
689
+ description: ctx.str("description") || void 0,
690
+ transport: ctx.str("transport") || "http",
691
+ headers: ctx.json("headers") || void 0,
692
+ scope: ctx.str("scope") || "personal"
693
+ };
694
+ const meta = buildMetaBody(ctx);
695
+ if (meta) body._meta = meta;
696
+ return { method: "POST", url: BASE_PATH3, body };
697
+ },
698
+ execute: async (ctx) => {
699
+ const created = await postAgentApi(ctx, BASE_PATH3, {
700
+ name: ctx.str("name"),
701
+ url: ctx.str("url"),
702
+ displayName: ctx.str("displayName") || void 0,
703
+ description: ctx.str("description") || void 0,
704
+ transport: ctx.str("transport") || "http",
705
+ headers: ctx.json("headers") || void 0,
706
+ scope: ctx.str("scope") || "personal"
707
+ });
708
+ const id = created?.item?.id;
709
+ const meta = buildMetaBody(ctx);
710
+ if (id && meta) {
711
+ try {
712
+ await patchAgentApi(ctx, `${MARKET_BASE_PATH}/${encodeURIComponent(id)}/meta`, meta);
713
+ } catch (err) {
714
+ process.stderr.write(`Warning: MCP created but meta update failed: ${err?.message ?? err}
715
+ `);
716
+ }
717
+ }
718
+ return created;
719
+ }
720
+ };
721
+ var delMcp = {
722
+ service: "agent",
723
+ command: "+del-mcp",
724
+ description: "Delete a personal MCP server",
725
+ flags: [
726
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" }
727
+ ],
728
+ risk: "high-risk-write",
729
+ dryRun: (ctx) => ({
730
+ method: "DELETE",
731
+ url: `${BASE_PATH3}?id=${encodeURIComponent(ctx.str("id"))}`
732
+ }),
733
+ execute: async (ctx) => {
734
+ return deleteAgentApi(ctx, `${BASE_PATH3}?id=${encodeURIComponent(ctx.str("id"))}`);
735
+ }
736
+ };
737
+ var toggleMcp = {
738
+ service: "agent",
739
+ command: "+toggle-mcp",
740
+ description: "Enable or disable an MCP server",
741
+ flags: [
742
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" },
743
+ { name: "enabled", type: "boolean", required: true, desc: "true to enable, false to disable" }
744
+ ],
745
+ risk: "write",
746
+ dryRun: (ctx) => ({
747
+ method: "PATCH",
748
+ url: BASE_PATH3,
749
+ body: { id: ctx.str("id"), enabled: ctx.bool("enabled") }
750
+ }),
751
+ execute: async (ctx) => {
752
+ return patchAgentApi(ctx, BASE_PATH3, {
753
+ id: ctx.str("id"),
754
+ enabled: ctx.bool("enabled")
755
+ });
756
+ }
757
+ };
758
+ var listMcpMarket = {
759
+ service: "agent",
760
+ command: "+list-mcp-market",
761
+ description: "List MCP servers from the market (system/company/personal)",
762
+ flags: [
763
+ { name: "scope", type: "string", required: false, default: "all", desc: `Market scope: ${MARKET_SCOPES.join(" | ")} (custom = personal)` },
764
+ { name: "category", type: "string", required: false, desc: `Category key: ${MARKET_CATEGORIES.join(" | ")}` },
765
+ { name: "search", type: "string", required: false, desc: "Fuzzy search on name/displayName/description/url" },
766
+ { name: "sort", type: "string", required: false, default: "newest", desc: `Sort: ${MARKET_SORTS.join(" | ")}` },
767
+ { name: "limit", type: "number", required: false, default: 50, desc: "Page size (1-100, default 50)" },
768
+ { name: "offset", type: "number", required: false, default: 0, desc: "Page offset (>=0, default 0)" }
769
+ ],
770
+ risk: "read",
771
+ validate: (ctx) => {
772
+ const scope = ctx.str("scope");
773
+ if (scope && !MARKET_SCOPES.includes(scope)) {
774
+ throw new Error(`--scope must be one of: ${MARKET_SCOPES.join(", ")}`);
775
+ }
776
+ const category = ctx.str("category");
777
+ if (category && !isValidMarketCategory(category)) {
778
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
779
+ }
780
+ const sort = ctx.str("sort");
781
+ if (sort && !MARKET_SORTS.includes(sort)) {
782
+ throw new Error(`--sort must be one of: ${MARKET_SORTS.join(", ")}`);
783
+ }
784
+ },
785
+ dryRun: (ctx) => ({
786
+ method: "GET",
787
+ url: `${MARKET_BASE_PATH}/market?${buildMarketQuery(ctx).toString()}`
788
+ }),
789
+ execute: async (ctx) => {
790
+ return getAgentApi(ctx, `${MARKET_BASE_PATH}/market?${buildMarketQuery(ctx).toString()}`);
791
+ }
792
+ };
793
+ var setMcpMeta = {
794
+ service: "agent",
795
+ command: "+set-mcp-meta",
796
+ description: "Update an MCP server market meta (category / icon). Company scope requires root; system is read-only.",
797
+ flags: [
798
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" },
799
+ { name: "category", type: "string", required: false, desc: `Category key: ${MARKET_CATEGORIES.join(" | ")}` },
800
+ { name: "icon-emoji", type: "string", required: false, desc: "Market icon emoji (e.g. robot)" },
801
+ { name: "icon-color", type: "string", required: false, desc: "Market icon color (e.g. #1E76F0)" }
802
+ ],
803
+ risk: "write",
804
+ validate: (ctx) => {
805
+ const category = ctx.str("category");
806
+ if (category && !isValidMarketCategory(category)) {
807
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
808
+ }
809
+ if (!buildMetaBody(ctx)) {
810
+ throw new Error("Provide at least one of --category / --icon-emoji / --icon-color");
811
+ }
812
+ },
813
+ dryRun: (ctx) => ({
814
+ method: "PATCH",
815
+ url: `${MARKET_BASE_PATH}/${encodeURIComponent(ctx.str("id"))}/meta`,
816
+ body: buildMetaBody(ctx)
817
+ }),
818
+ execute: async (ctx) => {
819
+ return patchAgentApi(
820
+ ctx,
821
+ `${MARKET_BASE_PATH}/${encodeURIComponent(ctx.str("id"))}/meta`,
822
+ buildMetaBody(ctx)
823
+ );
824
+ }
825
+ };
826
+ var UPDATE_TRANSPORTS = ["sse", "http", "streamable-http"];
827
+ var UPDATE_AUTH_MODES = ["none", "oauth2", "header", "manual"];
828
+ var CRED_AUTH_TYPES = ["oauth", "apikey"];
829
+ function buildUpdateBody(ctx) {
830
+ const body = {};
831
+ const name = ctx.str("name");
832
+ if (name) body.name = name;
833
+ const url = ctx.str("url");
834
+ if (url) body.url = url;
835
+ const displayName = ctx.str("displayName");
836
+ if (displayName) body.displayName = displayName;
837
+ const description = ctx.str("description");
838
+ if (description) body.description = description;
839
+ const transport = ctx.str("transport");
840
+ if (transport) body.transport = transport;
841
+ const headers = ctx.json("headers");
842
+ if (headers) body.headers = headers;
843
+ const secretHeaders = ctx.json("secretHeaders");
844
+ if (secretHeaders) body.secretHeaders = secretHeaders;
845
+ const authMode = ctx.str("authMode");
846
+ if (authMode) body.authMode = authMode;
847
+ const enabledStr = ctx.str("enabled");
848
+ if (enabledStr === "true") body.enabled = true;
849
+ else if (enabledStr === "false") body.enabled = false;
850
+ if (ctx.bool("autoRename")) body.autoRename = true;
851
+ return body;
852
+ }
853
+ var updateMcp = {
854
+ service: "agent",
855
+ command: "+update-mcp",
856
+ description: "Update an MCP server config (personal owner / company root / system read-only)",
857
+ flags: [
858
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" },
859
+ { name: "name", type: "string", required: false, desc: "Server name (2-64 chars, letter start, [a-zA-Z0-9_-])" },
860
+ { name: "url", type: "string", required: false, desc: "MCP server URL (http:// or https:// only)" },
861
+ { name: "display-name", type: "string", required: false, desc: "Display name (max 100)" },
862
+ { name: "description", type: "string", required: false, desc: "Description (max 255)" },
863
+ { name: "transport", type: "string", required: false, desc: `Transport: ${UPDATE_TRANSPORTS.join(" | ")}` },
864
+ { name: "headers", type: "json", required: false, desc: "HTTP headers as JSON object" },
865
+ { name: "secret-headers", type: "json", required: false, desc: "Secret headers as JSON object (encrypted server-side)" },
866
+ { name: "auth-mode", type: "string", required: false, desc: `Auth mode: ${UPDATE_AUTH_MODES.join(" | ")}` },
867
+ { name: "enabled", type: "string", required: false, desc: "Set enabled state: true | false (omit to leave unchanged)" },
868
+ { name: "auto-rename", type: "boolean", required: false, desc: "Auto-rename on name conflict (default false)" }
869
+ ],
870
+ risk: "write",
871
+ validate: (ctx) => {
872
+ const name = ctx.str("name");
873
+ if (name && !/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(name)) {
874
+ throw new Error("--name must start with a letter and contain only letters, digits, _, or -");
875
+ }
876
+ const url = ctx.str("url");
877
+ if (url) {
878
+ try {
879
+ new URL(url);
880
+ } catch {
881
+ throw new Error("--url must be a valid URL");
882
+ }
883
+ if (!/^https?:\/\//i.test(url)) {
884
+ throw new Error("--url only supports http:// or https:// protocols");
885
+ }
886
+ }
887
+ const transport = ctx.str("transport");
888
+ if (transport && !UPDATE_TRANSPORTS.includes(transport)) {
889
+ throw new Error(`--transport must be one of: ${UPDATE_TRANSPORTS.join(", ")}`);
890
+ }
891
+ const authMode = ctx.str("authMode");
892
+ if (authMode && !UPDATE_AUTH_MODES.includes(authMode)) {
893
+ throw new Error(`--auth-mode must be one of: ${UPDATE_AUTH_MODES.join(", ")}`);
894
+ }
895
+ const enabledStr = ctx.str("enabled");
896
+ if (enabledStr && enabledStr !== "true" && enabledStr !== "false") {
897
+ throw new Error("--enabled must be true or false");
898
+ }
899
+ const body = buildUpdateBody(ctx);
900
+ if (Object.keys(body).length === 0) {
901
+ throw new Error("Provide at least one field to update: --name / --url / --display-name / --description / --transport / --headers / --secret-headers / --auth-mode / --enabled / --auto-rename");
902
+ }
903
+ },
904
+ dryRun: (ctx) => ({
905
+ method: "PATCH",
906
+ url: `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}`,
907
+ body: buildUpdateBody(ctx)
908
+ }),
909
+ execute: async (ctx) => {
910
+ return patchAgentApi(
911
+ ctx,
912
+ `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}`,
913
+ buildUpdateBody(ctx)
914
+ );
915
+ }
916
+ };
917
+ var mcpTools = {
918
+ service: "agent",
919
+ command: "+mcp-tools",
920
+ description: "List tools exposed by an MCP server (with OAuth auto-refresh)",
921
+ flags: [
922
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" }
923
+ ],
924
+ risk: "read",
925
+ dryRun: (ctx) => ({
926
+ method: "GET",
927
+ url: `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/tools`
928
+ }),
929
+ execute: async (ctx) => {
930
+ return getAgentApi(ctx, `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/tools`);
931
+ }
932
+ };
933
+ var mcpAuthStart = {
934
+ service: "agent",
935
+ command: "+mcp-auth-start",
936
+ description: "Start MCP OAuth flow (CLI mode: get authorizeUrl, then poll +mcp-auth-status)",
937
+ flags: [
938
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" },
939
+ { name: "redirect-after", type: "string", required: false, desc: "URL to redirect to after OAuth completes (must be same-origin as the service base URL)" },
940
+ { name: "cli", type: "boolean", required: false, default: true, desc: "CLI mode (always true on sandbox endpoint; server derives the callback URL)" }
941
+ ],
942
+ risk: "write",
943
+ dryRun: (ctx) => ({
944
+ method: "POST",
945
+ url: `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/start`,
946
+ body: {
947
+ cliMode: true,
948
+ redirectAfter: ctx.str("redirectAfter") || void 0
949
+ }
950
+ }),
951
+ execute: async (ctx) => {
952
+ const result = await postAgentApi(
953
+ ctx,
954
+ `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/start`,
955
+ {
956
+ redirectAfter: ctx.str("redirectAfter") || void 0
957
+ }
958
+ );
959
+ if (result?.authorizeUrl && (process.stderr.isTTY || process.stdout.isTTY)) {
960
+ const id = ctx.str("id");
961
+ process.stderr.write(
962
+ `
963
+ \u8BF7\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u4EE5\u4E0B URL \u5B8C\u6210\u6388\u6743\uFF1A
964
+ ${result.authorizeUrl}
965
+
966
+ \u6388\u6743\u5B8C\u6210\u540E\uFF0C\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u8F6E\u8BE2\u6388\u6743\u72B6\u6001\uFF1A
967
+ ae-cli agent +mcp-auth-status --id ${id}
968
+
969
+ `
970
+ );
971
+ }
972
+ return result;
973
+ }
974
+ };
975
+ var mcpAuthStatus = {
976
+ service: "agent",
977
+ command: "+mcp-auth-status",
978
+ description: "Query MCP OAuth authorization status (CLI poll after +mcp-auth-start)",
979
+ flags: [
980
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" }
981
+ ],
982
+ risk: "read",
983
+ dryRun: (ctx) => ({
984
+ method: "GET",
985
+ url: `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/status`
986
+ }),
987
+ execute: async (ctx) => {
988
+ return getAgentApi(ctx, `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/status`);
989
+ }
990
+ };
991
+ var mcpAuthDisconnect = {
992
+ service: "agent",
993
+ command: "+mcp-auth-disconnect",
994
+ description: "Disconnect MCP OAuth (clears token and disables the server)",
995
+ flags: [
996
+ { name: "id", type: "string", required: true, desc: "MCP server record ID (CUID)" }
997
+ ],
998
+ risk: "write",
999
+ dryRun: (ctx) => ({
1000
+ method: "POST",
1001
+ url: `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/disconnect`
1002
+ }),
1003
+ execute: async (ctx) => {
1004
+ return postAgentApi(
1005
+ ctx,
1006
+ `${BASE_PATH3}/${encodeURIComponent(ctx.str("id"))}/auth/disconnect`,
1007
+ {}
1008
+ );
1009
+ }
1010
+ };
1011
+ var listMcpCredentials = {
1012
+ service: "agent",
1013
+ command: "+list-mcp-credentials",
1014
+ description: "List per-user credentials for system MCP servers",
1015
+ flags: [],
1016
+ risk: "read",
1017
+ dryRun: () => ({
1018
+ method: "GET",
1019
+ url: CRED_BASE_PATH
1020
+ }),
1021
+ execute: async (ctx) => {
1022
+ return getAgentApi(ctx, CRED_BASE_PATH);
1023
+ }
1024
+ };
1025
+ var setMcpCredential = {
1026
+ service: "agent",
1027
+ command: "+set-mcp-credential",
1028
+ description: "Upsert a per-user MCP credential (by mcpServerId + userId)",
1029
+ flags: [
1030
+ { name: "mcp-server-id", type: "string", required: true, desc: "System MCP server record ID (CUID)" },
1031
+ { name: "auth-type", type: "string", required: false, default: "oauth", desc: `Auth type: ${CRED_AUTH_TYPES.join(" | ")}` },
1032
+ { name: "token", type: "string", required: false, desc: "Token / API key (plaintext; encrypted server-side)" },
1033
+ { name: "expires-at", type: "string", required: false, desc: "ISO 8601 datetime (e.g. 2026-12-31T23:59:59Z)" }
1034
+ ],
1035
+ risk: "write",
1036
+ validate: (ctx) => {
1037
+ const authType = ctx.str("authType") || "oauth";
1038
+ if (!CRED_AUTH_TYPES.includes(authType)) {
1039
+ throw new Error(`--auth-type must be one of: ${CRED_AUTH_TYPES.join(", ")}`);
1040
+ }
1041
+ const expiresAt = ctx.str("expiresAt");
1042
+ if (expiresAt) {
1043
+ const d = new Date(expiresAt);
1044
+ if (isNaN(d.getTime())) {
1045
+ throw new Error("--expires-at must be a valid ISO 8601 datetime");
1046
+ }
1047
+ }
1048
+ },
1049
+ dryRun: (ctx) => ({
1050
+ method: "POST",
1051
+ url: CRED_BASE_PATH,
1052
+ body: {
1053
+ mcpServerId: ctx.str("mcpServerId"),
1054
+ authType: ctx.str("authType") || "oauth",
1055
+ token: ctx.str("token") || void 0,
1056
+ expiresAt: ctx.str("expiresAt") || void 0
1057
+ }
1058
+ }),
1059
+ execute: async (ctx) => {
1060
+ return postAgentApi(ctx, CRED_BASE_PATH, {
1061
+ mcpServerId: ctx.str("mcpServerId"),
1062
+ authType: ctx.str("authType") || "oauth",
1063
+ token: ctx.str("token") || void 0,
1064
+ expiresAt: ctx.str("expiresAt") || void 0
1065
+ });
1066
+ }
1067
+ };
1068
+ var autoProvisionMcpCredentials = {
1069
+ service: "agent",
1070
+ command: "+auto-provision-mcp-credentials",
1071
+ description: "Auto-provision credentials for all system MCP servers using the current access token",
1072
+ flags: [
1073
+ { name: "access-token", type: "string", required: false, desc: "Access token (defaults to the current session token from ctx.token())" }
1074
+ ],
1075
+ risk: "write",
1076
+ dryRun: (ctx) => ({
1077
+ method: "POST",
1078
+ url: `${CRED_BASE_PATH}/auto-provision`,
1079
+ body: {
1080
+ accessToken: ctx.str("accessToken") || "<current-session-token>"
1081
+ }
1082
+ }),
1083
+ execute: async (ctx) => {
1084
+ const accessToken = ctx.str("accessToken") || await ctx.token();
1085
+ return postAgentApi(ctx, `${CRED_BASE_PATH}/auto-provision`, { accessToken });
1086
+ }
1087
+ };
1088
+ var mcpToken = {
1089
+ service: "agent",
1090
+ command: "+mcp-token",
1091
+ description: "Get the plaintext MCP token (for useMcpToken=true system MCP servers)",
1092
+ flags: [],
1093
+ risk: "read",
1094
+ dryRun: () => ({
1095
+ method: "GET",
1096
+ url: `${CRED_BASE_PATH}/mcp-token`
1097
+ }),
1098
+ execute: async (ctx) => {
1099
+ const result = await getAgentApi(ctx, `${CRED_BASE_PATH}/mcp-token`);
1100
+ if (process.stderr.isTTY) {
1101
+ process.stderr.write(
1102
+ `
1103
+ \u6CE8\u610F\uFF1A\u8FD4\u56DE\u660E\u6587 MCP Token\uFF0C\u8BF7\u59A5\u5584\u4FDD\u7BA1\uFF0C\u907F\u514D\u5199\u5165 shell history \u6216\u65E5\u5FD7\u3002
1104
+
1105
+ `
1106
+ );
1107
+ }
1108
+ return result;
1109
+ }
1110
+ };
1111
+ var mcpStats = {
1112
+ service: "agent",
1113
+ command: "+mcp-stats",
1114
+ description: "Show MCP call statistics for the last N days (by server / by day)",
1115
+ flags: [
1116
+ { name: "days", type: "number", required: false, default: 30, desc: "Lookback window in days (1-365, default 30)" }
1117
+ ],
1118
+ risk: "read",
1119
+ validate: (ctx) => {
1120
+ const days = ctx.optionalNum("days");
1121
+ if (days !== void 0 && (!Number.isInteger(days) || days < 1 || days > 365)) {
1122
+ throw new Error("--days must be an integer between 1 and 365");
1123
+ }
1124
+ },
1125
+ dryRun: (ctx) => {
1126
+ const days = ctx.optionalNum("days") ?? 30;
1127
+ return { method: "GET", url: `${STATS_PATH}?days=${days}` };
1128
+ },
1129
+ execute: async (ctx) => {
1130
+ const days = ctx.optionalNum("days") ?? 30;
1131
+ return getAgentApi(ctx, `${STATS_PATH}?days=${days}`);
1132
+ }
1133
+ };
1134
+
1135
+ // src/commands/te-agent/skills.ts
1136
+ var BASE_PATH4 = "/api/sandbox/agent/skills";
1137
+ var MARKET_BASE_PATH2 = "/api/sandbox/agent/skills";
1138
+ function buildMetaBody2(ctx) {
1139
+ const body = {};
1140
+ const category = ctx.str("category");
1141
+ const iconEmoji = ctx.str("iconEmoji");
1142
+ const iconColor = ctx.str("iconColor");
1143
+ if (category) body.category = category;
1144
+ if (iconEmoji) body.iconEmoji = iconEmoji;
1145
+ if (iconColor) body.iconColor = iconColor;
1146
+ return Object.keys(body).length > 0 ? body : null;
1147
+ }
1148
+ async function resolveInstructions2(raw) {
1149
+ if (raw === "@-") {
1150
+ const chunks = [];
1151
+ for await (const chunk of process.stdin) {
1152
+ chunks.push(chunk);
1153
+ }
1154
+ const text = Buffer.concat(chunks).toString("utf8").trim();
1155
+ if (!text) throw new Error("stdin is empty; cannot read instructions");
1156
+ return text;
1157
+ }
1158
+ return raw;
1159
+ }
1160
+ var listSkills = {
1161
+ service: "agent",
1162
+ command: "+list-skills",
1163
+ description: "List Skills visible to current user",
1164
+ flags: [
1165
+ {
1166
+ name: "scope",
1167
+ type: "string",
1168
+ required: false,
1169
+ desc: "Filter by scope: personal | company | system"
1170
+ }
1171
+ ],
1172
+ risk: "read",
1173
+ validate: (ctx) => {
1174
+ const scope = ctx.str("scope");
1175
+ if (scope && !["personal", "company", "system"].includes(scope)) {
1176
+ throw new Error("--scope must be personal, company, or system");
1177
+ }
1178
+ },
1179
+ dryRun: (ctx) => {
1180
+ const scope = ctx.str("scope");
1181
+ const qs = scope ? `?scope=${encodeURIComponent(scope)}` : "";
1182
+ return { method: "GET", url: `${BASE_PATH4}${qs}` };
1183
+ },
1184
+ execute: async (ctx) => {
1185
+ const scope = ctx.str("scope");
1186
+ const qs = scope ? `?scope=${encodeURIComponent(scope)}` : "";
1187
+ return getAgentApi(ctx, `${BASE_PATH4}${qs}`);
1188
+ }
1189
+ };
1190
+ var addSkill = {
1191
+ service: "agent",
1192
+ command: "+add-skill",
1193
+ description: "Create a custom Skill (personal or company scope)",
1194
+ flags: [
1195
+ {
1196
+ name: "name",
1197
+ type: "string",
1198
+ required: true,
1199
+ desc: "Skill name (1-80 chars)"
1200
+ },
1201
+ {
1202
+ name: "description",
1203
+ type: "string",
1204
+ required: true,
1205
+ desc: "Skill description"
1206
+ },
1207
+ {
1208
+ name: "instructions",
1209
+ type: "string",
1210
+ required: true,
1211
+ desc: "Skill instructions (use @- to read from stdin)"
1212
+ },
1213
+ {
1214
+ name: "display-name",
1215
+ type: "string",
1216
+ required: false,
1217
+ desc: "Display name (max 100)"
1218
+ },
1219
+ {
1220
+ name: "category",
1221
+ type: "string",
1222
+ required: false,
1223
+ desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}`
1224
+ },
1225
+ {
1226
+ name: "icon-emoji",
1227
+ type: "string",
1228
+ required: false,
1229
+ desc: "Market icon emoji (e.g. robot)"
1230
+ },
1231
+ {
1232
+ name: "icon-color",
1233
+ type: "string",
1234
+ required: false,
1235
+ desc: "Market icon color (e.g. #1E76F0)"
1236
+ },
1237
+ {
1238
+ name: "scope",
1239
+ type: "string",
1240
+ required: false,
1241
+ default: "personal",
1242
+ desc: "Target scope: personal | company"
1243
+ },
1244
+ {
1245
+ name: "version",
1246
+ type: "string",
1247
+ required: false,
1248
+ desc: "Initial content version (major.minor; default 1.0)"
1249
+ }
1250
+ ],
1251
+ risk: "write",
1252
+ validate: (ctx) => {
1253
+ const name = ctx.str("name");
1254
+ if (name.length < 1 || name.length > 80) {
1255
+ throw new Error("--name length must be between 1 and 80");
1256
+ }
1257
+ const category = ctx.str("category");
1258
+ if (category && !isValidMarketCategory(category)) {
1259
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
1260
+ }
1261
+ const scope = ctx.str("scope");
1262
+ if (scope && !["personal", "company"].includes(scope)) {
1263
+ throw new Error("--scope must be personal or company");
1264
+ }
1265
+ const version = ctx.str("version");
1266
+ if (version) assertValidSkillVersion(version);
1267
+ },
1268
+ dryRun: (ctx) => {
1269
+ const body = {
1270
+ name: ctx.str("name"),
1271
+ description: ctx.str("description"),
1272
+ instructions: ctx.str("instructions") === "@-" ? "(from stdin)" : ctx.str("instructions"),
1273
+ displayName: ctx.str("displayName") || void 0,
1274
+ scope: ctx.str("scope") || "personal",
1275
+ version: ctx.str("version") || void 0
1276
+ };
1277
+ const meta = buildMetaBody2(ctx);
1278
+ if (meta) body._meta = meta;
1279
+ return { method: "POST", url: BASE_PATH4, body };
1280
+ },
1281
+ execute: async (ctx) => {
1282
+ const instructions = await resolveInstructions2(ctx.str("instructions"));
1283
+ const created = await postAgentApi(ctx, BASE_PATH4, {
1284
+ name: ctx.str("name"),
1285
+ description: ctx.str("description"),
1286
+ instructions,
1287
+ displayName: ctx.str("displayName") || void 0,
1288
+ scope: ctx.str("scope") || "personal",
1289
+ version: ctx.str("version") || void 0
1290
+ });
1291
+ const id = created?.item?.id;
1292
+ const meta = buildMetaBody2(ctx);
1293
+ if (id && meta) {
1294
+ try {
1295
+ await patchAgentApi(ctx, `${MARKET_BASE_PATH2}/${encodeURIComponent(id)}/meta`, meta);
1296
+ } catch (err) {
1297
+ process.stderr.write(`Warning: Skill created but meta update failed: ${err?.message ?? err}
1298
+ `);
1299
+ }
1300
+ }
1301
+ return created;
1302
+ }
1303
+ };
1304
+ var delSkill = {
1305
+ service: "agent",
1306
+ command: "+del-skill",
1307
+ description: "Delete a personal Skill (physical delete)",
1308
+ flags: [
1309
+ {
1310
+ name: "id",
1311
+ type: "string",
1312
+ required: true,
1313
+ desc: "Skill record ID (CUID)"
1314
+ }
1315
+ ],
1316
+ risk: "high-risk-write",
1317
+ dryRun: (ctx) => ({
1318
+ method: "DELETE",
1319
+ url: `${BASE_PATH4}?id=${encodeURIComponent(ctx.str("id"))}`
1320
+ }),
1321
+ execute: async (ctx) => {
1322
+ return deleteAgentApi(ctx, `${BASE_PATH4}?id=${encodeURIComponent(ctx.str("id"))}`);
1323
+ }
1324
+ };
1325
+ var toggleSkill = {
1326
+ service: "agent",
1327
+ command: "+toggle-skill",
1328
+ description: "Enable or disable a Skill",
1329
+ flags: [
1330
+ {
1331
+ name: "id",
1332
+ type: "string",
1333
+ required: true,
1334
+ desc: "Skill record ID (CUID)"
1335
+ },
1336
+ {
1337
+ name: "enabled",
1338
+ type: "boolean",
1339
+ required: true,
1340
+ desc: "true to enable, false to disable"
1341
+ }
1342
+ ],
1343
+ risk: "write",
1344
+ dryRun: (ctx) => ({
1345
+ method: "PATCH",
1346
+ url: BASE_PATH4,
1347
+ body: { id: ctx.str("id"), enabled: ctx.bool("enabled") }
1348
+ }),
1349
+ execute: async (ctx) => {
1350
+ return patchAgentApi(ctx, BASE_PATH4, {
1351
+ id: ctx.str("id"),
1352
+ enabled: ctx.bool("enabled")
1353
+ });
1354
+ }
1355
+ };
1356
+ var listSkillMarket = {
1357
+ service: "agent",
1358
+ command: "+list-skill-market",
1359
+ description: "List Skills from the market (only approved items; system/company/personal)",
1360
+ flags: [
1361
+ {
1362
+ name: "scope",
1363
+ type: "string",
1364
+ required: false,
1365
+ default: "all",
1366
+ desc: `Market scope: ${MARKET_SCOPES.join(" | ")} (custom = personal)`
1367
+ },
1368
+ {
1369
+ name: "category",
1370
+ type: "string",
1371
+ required: false,
1372
+ desc: `Category key: ${MARKET_CATEGORIES.join(" | ")}`
1373
+ },
1374
+ {
1375
+ name: "search",
1376
+ type: "string",
1377
+ required: false,
1378
+ desc: "Fuzzy search on name/displayName/description"
1379
+ },
1380
+ {
1381
+ name: "sort",
1382
+ type: "string",
1383
+ required: false,
1384
+ default: "newest",
1385
+ desc: `Sort: ${MARKET_SORTS.join(" | ")} (calls = downloads)`
1386
+ },
1387
+ {
1388
+ name: "limit",
1389
+ type: "number",
1390
+ required: false,
1391
+ default: 50,
1392
+ desc: "Page size (1-100, default 50)"
1393
+ },
1394
+ {
1395
+ name: "offset",
1396
+ type: "number",
1397
+ required: false,
1398
+ default: 0,
1399
+ desc: "Page offset (>=0, default 0)"
1400
+ }
1401
+ ],
1402
+ risk: "read",
1403
+ validate: (ctx) => {
1404
+ const scope = ctx.str("scope");
1405
+ if (scope && !MARKET_SCOPES.includes(scope)) {
1406
+ throw new Error(`--scope must be one of: ${MARKET_SCOPES.join(", ")}`);
1407
+ }
1408
+ const category = ctx.str("category");
1409
+ if (category && !isValidMarketCategory(category)) {
1410
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
1411
+ }
1412
+ const sort = ctx.str("sort");
1413
+ if (sort && !MARKET_SORTS.includes(sort)) {
1414
+ throw new Error(`--sort must be one of: ${MARKET_SORTS.join(", ")}`);
1415
+ }
1416
+ },
1417
+ dryRun: (ctx) => ({
1418
+ method: "GET",
1419
+ url: `${MARKET_BASE_PATH2}/market?${buildMarketQuery(ctx).toString()}`
1420
+ }),
1421
+ execute: async (ctx) => {
1422
+ return getAgentApi(ctx, `${MARKET_BASE_PATH2}/market?${buildMarketQuery(ctx).toString()}`);
1423
+ }
1424
+ };
1425
+ var setSkillMeta = {
1426
+ service: "agent",
1427
+ command: "+set-skill-meta",
1428
+ description: "Update a Skill market meta (category / icon). Company scope requires root; system is read-only.",
1429
+ flags: [
1430
+ {
1431
+ name: "id",
1432
+ type: "string",
1433
+ required: true,
1434
+ desc: "Skill record ID (CUID)"
1435
+ },
1436
+ {
1437
+ name: "category",
1438
+ type: "string",
1439
+ required: false,
1440
+ desc: `Category key: ${MARKET_CATEGORIES.join(" | ")}`
1441
+ },
1442
+ {
1443
+ name: "icon-emoji",
1444
+ type: "string",
1445
+ required: false,
1446
+ desc: "Market icon emoji (e.g. robot)"
1447
+ },
1448
+ {
1449
+ name: "icon-color",
1450
+ type: "string",
1451
+ required: false,
1452
+ desc: "Market icon color (e.g. #1E76F0)"
1453
+ }
1454
+ ],
1455
+ risk: "write",
1456
+ validate: (ctx) => {
1457
+ const category = ctx.str("category");
1458
+ if (category && !isValidMarketCategory(category)) {
1459
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
1460
+ }
1461
+ if (!buildMetaBody2(ctx)) {
1462
+ throw new Error("Provide at least one of --category / --icon-emoji / --icon-color");
1463
+ }
1464
+ },
1465
+ dryRun: (ctx) => ({
1466
+ method: "PATCH",
1467
+ url: `${MARKET_BASE_PATH2}/${encodeURIComponent(ctx.str("id"))}/meta`,
1468
+ body: buildMetaBody2(ctx)
1469
+ }),
1470
+ execute: async (ctx) => {
1471
+ return patchAgentApi(ctx, `${MARKET_BASE_PATH2}/${encodeURIComponent(ctx.str("id"))}/meta`, buildMetaBody2(ctx));
1472
+ }
1473
+ };
1474
+ var copySkill = {
1475
+ service: "agent",
1476
+ command: "+copy-skill",
1477
+ description: "Copy a system/company Skill to a personal copy (independent duplicate)",
1478
+ flags: [
1479
+ {
1480
+ name: "id",
1481
+ type: "string",
1482
+ required: true,
1483
+ desc: "Source Skill record ID (CUID, system or company scope)"
1484
+ },
1485
+ {
1486
+ name: "category",
1487
+ type: "string",
1488
+ required: false,
1489
+ desc: `Market category key for the copy: ${MARKET_CATEGORIES.join(" | ")}`
1490
+ },
1491
+ {
1492
+ name: "icon-emoji",
1493
+ type: "string",
1494
+ required: false,
1495
+ desc: "Override market icon emoji (e.g. robot)"
1496
+ },
1497
+ {
1498
+ name: "icon-color",
1499
+ type: "string",
1500
+ required: false,
1501
+ desc: "Override market icon color (e.g. #1E76F0)"
1502
+ }
1503
+ ],
1504
+ risk: "write",
1505
+ validate: (ctx) => {
1506
+ const category = ctx.str("category");
1507
+ if (category && !isValidMarketCategory(category)) {
1508
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
1509
+ }
1510
+ },
1511
+ dryRun: (ctx) => ({
1512
+ method: "POST",
1513
+ url: `${MARKET_BASE_PATH2}/${encodeURIComponent(ctx.str("id"))}/copy`,
1514
+ body: buildMetaBody2(ctx) ?? {}
1515
+ }),
1516
+ execute: async (ctx) => {
1517
+ return postAgentApi(ctx, `${MARKET_BASE_PATH2}/${encodeURIComponent(ctx.str("id"))}/copy`, buildMetaBody2(ctx) ?? {});
1518
+ }
1519
+ };
1520
+
1521
+ // src/commands/te-agent/skill-content.ts
1522
+ import { readFileSync, existsSync, writeFileSync } from "fs";
1523
+ import { resolve, basename, extname } from "path";
1524
+ var BASE_PATH5 = "/api/sandbox/agent/skills";
1525
+ async function resolveInstructions3(raw) {
1526
+ if (raw === "@-") {
1527
+ const chunks = [];
1528
+ for await (const chunk of process.stdin) {
1529
+ chunks.push(chunk);
1530
+ }
1531
+ const text = Buffer.concat(chunks).toString("utf8").trim();
1532
+ if (!text) throw new Error("stdin is empty; cannot read instructions");
1533
+ return text;
1534
+ }
1535
+ return raw;
1536
+ }
1537
+ function readFileForUpload(filePath) {
1538
+ const resolved = resolve(filePath);
1539
+ if (!existsSync(resolved)) {
1540
+ throw new Error(`File not found: ${resolved}`);
1541
+ }
1542
+ const buffer = readFileSync(resolved);
1543
+ const fileName = basename(resolved);
1544
+ const mimeType = guessMimeType(resolved);
1545
+ return { buffer, fileName, mimeType };
1546
+ }
1547
+ function guessMimeType(filePath) {
1548
+ const ext = extname(filePath).toLowerCase();
1549
+ const map = {
1550
+ ".png": "image/png",
1551
+ ".jpg": "image/jpeg",
1552
+ ".jpeg": "image/jpeg",
1553
+ ".gif": "image/gif",
1554
+ ".webp": "image/webp",
1555
+ ".svg": "image/svg+xml",
1556
+ ".pdf": "application/pdf",
1557
+ ".md": "text/markdown",
1558
+ ".txt": "text/plain",
1559
+ ".csv": "text/csv",
1560
+ ".json": "application/json",
1561
+ ".html": "text/html",
1562
+ ".xml": "application/xml",
1563
+ ".doc": "application/msword",
1564
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1565
+ ".xls": "application/vnd.ms-excel",
1566
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1567
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1568
+ ".zip": "application/zip"
1569
+ };
1570
+ return map[ext] || "application/octet-stream";
1571
+ }
1572
+ function buildAssetFormData(filePath, subPath) {
1573
+ const { buffer, fileName, mimeType } = readFileForUpload(filePath);
1574
+ const fd = new FormData();
1575
+ const blob = new Blob([new Uint8Array(buffer)], { type: mimeType });
1576
+ fd.append("file", blob, fileName);
1577
+ if (subPath) fd.append("subPath", subPath);
1578
+ return fd;
1579
+ }
1580
+ function makeAssetListCommand(commandName, description, dirName) {
1581
+ return {
1582
+ service: "agent",
1583
+ command: commandName,
1584
+ description,
1585
+ flags: [
1586
+ {
1587
+ name: "id",
1588
+ type: "string",
1589
+ required: true,
1590
+ desc: "Skill record ID (CUID)"
1591
+ }
1592
+ ],
1593
+ risk: "read",
1594
+ dryRun: (ctx) => ({
1595
+ method: "GET",
1596
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}`
1597
+ }),
1598
+ execute: async (ctx) => {
1599
+ return getAgentApi(ctx, `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}`);
1600
+ }
1601
+ };
1602
+ }
1603
+ function makeAssetUploadCommand(commandName, description, dirName) {
1604
+ const validate = (ctx) => {
1605
+ const filePath = ctx.str("file");
1606
+ if (!filePath) throw new Error("--file is required");
1607
+ if (!existsSync(resolve(filePath))) throw new Error(`File not found: ${resolve(filePath)}`);
1608
+ };
1609
+ return {
1610
+ service: "agent",
1611
+ command: commandName,
1612
+ description,
1613
+ flags: [
1614
+ {
1615
+ name: "id",
1616
+ type: "string",
1617
+ required: true,
1618
+ desc: "Skill record ID (CUID)"
1619
+ },
1620
+ {
1621
+ name: "file",
1622
+ type: "string",
1623
+ required: true,
1624
+ desc: "Local file path to upload (max 1MB)"
1625
+ },
1626
+ {
1627
+ name: "sub-path",
1628
+ type: "string",
1629
+ required: false,
1630
+ desc: 'Sub-directory under the target dir (e.g. "sub/")'
1631
+ }
1632
+ ],
1633
+ risk: "write",
1634
+ validate,
1635
+ dryRun: (ctx) => ({
1636
+ method: "POST",
1637
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}`,
1638
+ body: { file: ctx.str("file"), subPath: ctx.str("subPath") || "" }
1639
+ }),
1640
+ execute: async (ctx) => {
1641
+ const fd = buildAssetFormData(ctx.str("file"), ctx.str("subPath") || void 0);
1642
+ return uploadAgentApi(ctx, `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}`, fd);
1643
+ }
1644
+ };
1645
+ }
1646
+ function isTextContentType(contentType) {
1647
+ const mediaType = contentType?.split(";", 1)[0]?.trim().toLowerCase();
1648
+ if (!mediaType) return false;
1649
+ return mediaType.startsWith("text/") || mediaType === "application/json" || mediaType.endsWith("+json") || mediaType === "application/xml" || mediaType.endsWith("+xml");
1650
+ }
1651
+ function makeAssetReadCommand(commandName, description, dirName) {
1652
+ return {
1653
+ service: "agent",
1654
+ command: commandName,
1655
+ description,
1656
+ flags: [
1657
+ {
1658
+ name: "id",
1659
+ type: "string",
1660
+ required: true,
1661
+ desc: "Skill record ID (CUID)"
1662
+ },
1663
+ {
1664
+ name: "path",
1665
+ type: "string",
1666
+ required: true,
1667
+ desc: 'Relative file path within the directory (e.g. "guide.md" or "sub/icon.png")'
1668
+ },
1669
+ {
1670
+ name: "output",
1671
+ type: "string",
1672
+ required: false,
1673
+ desc: "Write binary content to a local file (preserves binary data)"
1674
+ }
1675
+ ],
1676
+ risk: "read",
1677
+ dryRun: (ctx) => ({
1678
+ method: "GET",
1679
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}/${encodeURIComponent(ctx.str("path"))}`
1680
+ }),
1681
+ execute: async (ctx) => {
1682
+ const filePath = ctx.str("path");
1683
+ const encodedPath = filePath.split("/").map((seg) => encodeURIComponent(seg)).join("/");
1684
+ const url = `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}/${encodedPath}`;
1685
+ const { buffer, fileName, contentType } = await getAgentBuffer(ctx, url);
1686
+ const outputPath = ctx.str("output");
1687
+ if (outputPath) {
1688
+ const resolved = resolve(outputPath);
1689
+ writeFileSync(resolved, buffer);
1690
+ return { saved: true, path: resolved, size: buffer.length, fileName };
1691
+ }
1692
+ if (dirName === "references" && !isTextContentType(contentType)) {
1693
+ throw new CliValidationError("Binary content requires --output", {
1694
+ code: "output_required",
1695
+ hint: "Re-run with --output <path> to preserve the original bytes."
1696
+ });
1697
+ }
1698
+ const content = buffer.toString("utf8");
1699
+ return { content, fileName };
1700
+ }
1701
+ };
1702
+ }
1703
+ function makeAssetDelCommand(commandName, description, dirName) {
1704
+ return {
1705
+ service: "agent",
1706
+ command: commandName,
1707
+ description,
1708
+ flags: [
1709
+ {
1710
+ name: "id",
1711
+ type: "string",
1712
+ required: true,
1713
+ desc: "Skill record ID (CUID)"
1714
+ },
1715
+ {
1716
+ name: "path",
1717
+ type: "string",
1718
+ required: true,
1719
+ desc: "Relative file path within the directory to delete"
1720
+ }
1721
+ ],
1722
+ risk: "high-risk-write",
1723
+ dryRun: (ctx) => ({
1724
+ method: "DELETE",
1725
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}/${encodeURIComponent(ctx.str("path"))}`
1726
+ }),
1727
+ execute: async (ctx) => {
1728
+ const filePath = ctx.str("path");
1729
+ const encodedPath = filePath.split("/").map((seg) => encodeURIComponent(seg)).join("/");
1730
+ return deleteAgentApi(ctx, `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/${dirName}/${encodedPath}`);
1731
+ }
1732
+ };
1733
+ }
1734
+ var editSkill = {
1735
+ service: "agent",
1736
+ command: "+edit-skill",
1737
+ description: "Edit a personal Skill content (name / description / instructions / icon)",
1738
+ flags: [
1739
+ {
1740
+ name: "id",
1741
+ type: "string",
1742
+ required: true,
1743
+ desc: "Skill record ID (CUID)"
1744
+ },
1745
+ {
1746
+ name: "name",
1747
+ type: "string",
1748
+ required: false,
1749
+ desc: "New Skill name (1-80 chars)"
1750
+ },
1751
+ {
1752
+ name: "description",
1753
+ type: "string",
1754
+ required: false,
1755
+ desc: "New Skill description"
1756
+ },
1757
+ {
1758
+ name: "instructions",
1759
+ type: "string",
1760
+ required: false,
1761
+ desc: "New instructions (use @- to read from stdin)"
1762
+ },
1763
+ {
1764
+ name: "display-name",
1765
+ type: "string",
1766
+ required: false,
1767
+ desc: "New display name (max 100)"
1768
+ },
1769
+ {
1770
+ name: "category",
1771
+ type: "string",
1772
+ required: false,
1773
+ desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}`
1774
+ },
1775
+ {
1776
+ name: "icon-emoji",
1777
+ type: "string",
1778
+ required: false,
1779
+ desc: "Market icon emoji (e.g. robot)"
1780
+ },
1781
+ {
1782
+ name: "icon-color",
1783
+ type: "string",
1784
+ required: false,
1785
+ desc: "Market icon color (e.g. #1E76F0)"
1786
+ },
1787
+ {
1788
+ name: "version",
1789
+ type: "string",
1790
+ required: false,
1791
+ desc: "New content version (major.minor; required for content changes)"
1792
+ }
1793
+ ],
1794
+ risk: "write",
1795
+ validate: (ctx) => {
1796
+ const name = ctx.str("name");
1797
+ if (name && (name.length < 1 || name.length > 80)) {
1798
+ throw new Error("--name length must be between 1 and 80");
1799
+ }
1800
+ const category = ctx.str("category");
1801
+ if (category && !isValidMarketCategory(category)) {
1802
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
1803
+ }
1804
+ const hasAny = ctx.str("name") || ctx.str("description") || ctx.str("instructions") || ctx.str("displayName") || ctx.str("category") || ctx.str("iconEmoji") || ctx.str("iconColor");
1805
+ if (!hasAny) {
1806
+ throw new Error(
1807
+ "Provide at least one of --name / --description / --instructions / --display-name / --category / --icon-emoji / --icon-color"
1808
+ );
1809
+ }
1810
+ const version = ctx.str("version");
1811
+ if (version) assertValidSkillVersion(version);
1812
+ const changesContent = Boolean(ctx.str("name")) || Boolean(ctx.str("description")) || Boolean(ctx.str("instructions"));
1813
+ if (changesContent && !version) {
1814
+ throw new Error("--version is required when editing Skill content");
1815
+ }
1816
+ },
1817
+ dryRun: (ctx) => {
1818
+ const body = {};
1819
+ if (ctx.str("name")) body.name = ctx.str("name");
1820
+ if (ctx.str("description")) body.description = ctx.str("description");
1821
+ body.instructions = ctx.str("instructions") === "@-" ? "(from stdin)" : ctx.str("instructions") || void 0;
1822
+ if (ctx.str("displayName")) body.displayName = ctx.str("displayName");
1823
+ if (ctx.str("category")) body.category = ctx.str("category");
1824
+ if (ctx.str("iconEmoji")) body.iconEmoji = ctx.str("iconEmoji");
1825
+ if (ctx.str("iconColor")) body.iconColor = ctx.str("iconColor");
1826
+ if (ctx.str("version")) body.version = ctx.str("version");
1827
+ return {
1828
+ method: "PUT",
1829
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}`,
1830
+ body
1831
+ };
1832
+ },
1833
+ execute: async (ctx) => {
1834
+ const body = {};
1835
+ if (ctx.str("name")) body.name = ctx.str("name");
1836
+ if (ctx.str("description")) body.description = ctx.str("description");
1837
+ if (ctx.str("instructions")) {
1838
+ body.instructions = await resolveInstructions3(ctx.str("instructions"));
1839
+ }
1840
+ if (ctx.str("displayName")) body.displayName = ctx.str("displayName");
1841
+ if (ctx.str("category")) body.category = ctx.str("category");
1842
+ if (ctx.str("iconEmoji")) body.iconEmoji = ctx.str("iconEmoji");
1843
+ if (ctx.str("iconColor")) body.iconColor = ctx.str("iconColor");
1844
+ if (ctx.str("version")) body.version = ctx.str("version");
1845
+ return putAgentApi(ctx, `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}`, body);
1846
+ }
1847
+ };
1848
+ var getSkillContent = {
1849
+ service: "agent",
1850
+ command: "+get-skill-content",
1851
+ description: "Read a Skill SKILL.md text content",
1852
+ flags: [
1853
+ {
1854
+ name: "id",
1855
+ type: "string",
1856
+ required: true,
1857
+ desc: "Skill record ID (CUID)"
1858
+ }
1859
+ ],
1860
+ risk: "read",
1861
+ dryRun: (ctx) => ({
1862
+ method: "GET",
1863
+ url: `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/content`
1864
+ }),
1865
+ execute: async (ctx) => {
1866
+ return getAgentApi(ctx, `${BASE_PATH5}/${encodeURIComponent(ctx.str("id"))}/content`);
1867
+ }
1868
+ };
1869
+ var listSkillAssets = makeAssetListCommand(
1870
+ "+list-skill-assets",
1871
+ "List all files in a Skill assets directory",
1872
+ "assets"
1873
+ );
1874
+ var uploadSkillAsset = makeAssetUploadCommand(
1875
+ "+upload-skill-asset",
1876
+ "Upload a single file to a Skill assets directory (max 1MB)",
1877
+ "assets"
1878
+ );
1879
+ var readSkillAsset = makeAssetReadCommand(
1880
+ "+read-skill-asset",
1881
+ "Read a Skill asset file (binary-safe; use --output to save to disk)",
1882
+ "assets"
1883
+ );
1884
+ var delSkillAsset = makeAssetDelCommand(
1885
+ "+del-skill-asset",
1886
+ "Delete a file from a Skill assets directory",
1887
+ "assets"
1888
+ );
1889
+ var listSkillReferences = makeAssetListCommand(
1890
+ "+list-skill-references",
1891
+ "List all files in a Skill references directory",
1892
+ "references"
1893
+ );
1894
+ var uploadSkillReference = makeAssetUploadCommand(
1895
+ "+upload-skill-reference",
1896
+ "Upload a single file to a Skill references directory (max 1MB)",
1897
+ "references"
1898
+ );
1899
+ var readSkillReference = makeAssetReadCommand(
1900
+ "+read-skill-reference",
1901
+ "Read a Skill reference file (binary-safe; use --output for non-text files)",
1902
+ "references"
1903
+ );
1904
+ var delSkillReference = makeAssetDelCommand(
1905
+ "+del-skill-reference",
1906
+ "Delete a file from a Skill references directory",
1907
+ "references"
1908
+ );
1909
+ var listSkillScripts = makeAssetListCommand(
1910
+ "+list-skill-scripts",
1911
+ "List all files in a Skill scripts directory",
1912
+ "scripts"
1913
+ );
1914
+ var uploadSkillScript = makeAssetUploadCommand(
1915
+ "+upload-skill-script",
1916
+ "Upload a single file to a Skill scripts directory (max 1MB)",
1917
+ "scripts"
1918
+ );
1919
+ var readSkillScript = makeAssetReadCommand(
1920
+ "+read-skill-script",
1921
+ "Read a Skill script file (binary-safe; use --output to save to disk)",
1922
+ "scripts"
1923
+ );
1924
+ var delSkillScript = makeAssetDelCommand(
1925
+ "+del-skill-script",
1926
+ "Delete a file from a Skill scripts directory",
1927
+ "scripts"
1928
+ );
1929
+ var uploadSkill = {
1930
+ service: "agent",
1931
+ command: "+upload-skill",
1932
+ description: "Upload a ZIP-format Skill (parses SKILL.md + extracts to target dir)",
1933
+ flags: [
1934
+ {
1935
+ name: "file",
1936
+ type: "string",
1937
+ required: true,
1938
+ desc: "Local .zip file path"
1939
+ },
1940
+ {
1941
+ name: "scope",
1942
+ type: "string",
1943
+ required: false,
1944
+ default: "personal",
1945
+ desc: "Target scope: personal | company"
1946
+ },
1947
+ {
1948
+ name: "auto-rename",
1949
+ type: "boolean",
1950
+ required: false,
1951
+ desc: "Auto-rename on name conflict"
1952
+ },
1953
+ {
1954
+ name: "replace-skill-id",
1955
+ type: "string",
1956
+ required: false,
1957
+ desc: "Replace an existing Skill (CUID) instead of creating a new one"
1958
+ },
1959
+ {
1960
+ name: "category",
1961
+ type: "string",
1962
+ required: false,
1963
+ desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}`
1964
+ },
1965
+ {
1966
+ name: "name",
1967
+ type: "string",
1968
+ required: false,
1969
+ desc: "Override Skill name (from ZIP SKILL.md if omitted)"
1970
+ },
1971
+ {
1972
+ name: "display-name",
1973
+ type: "string",
1974
+ required: false,
1975
+ desc: "Override display name"
1976
+ },
1977
+ {
1978
+ name: "description",
1979
+ type: "string",
1980
+ required: false,
1981
+ desc: "Override description"
1982
+ },
1983
+ {
1984
+ name: "instructions",
1985
+ type: "string",
1986
+ required: false,
1987
+ desc: "Override instructions (use @- to read from stdin)"
1988
+ },
1989
+ {
1990
+ name: "icon-emoji",
1991
+ type: "string",
1992
+ required: false,
1993
+ desc: "Market icon emoji (e.g. robot)"
1994
+ },
1995
+ {
1996
+ name: "icon-color",
1997
+ type: "string",
1998
+ required: false,
1999
+ desc: "Market icon color (e.g. #1E76F0)"
2000
+ },
2001
+ {
2002
+ name: "version",
2003
+ type: "string",
2004
+ required: false,
2005
+ desc: "Content version (major.minor; required with --replace-skill-id)"
2006
+ }
2007
+ ],
2008
+ risk: "write",
2009
+ validate: (ctx) => {
2010
+ const filePath = ctx.str("file");
2011
+ if (!filePath) throw new Error("--file is required");
2012
+ const resolved = resolve(filePath);
2013
+ if (!existsSync(resolved)) throw new Error(`File not found: ${resolved}`);
2014
+ const ext = extname(resolved).toLowerCase();
2015
+ if (ext !== ".zip") throw new Error("--file must be a .zip file");
2016
+ const scope = ctx.str("scope");
2017
+ if (scope && !["personal", "company"].includes(scope)) {
2018
+ throw new Error("--scope must be personal or company");
2019
+ }
2020
+ const category = ctx.str("category");
2021
+ if (category && !isValidMarketCategory(category)) {
2022
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
2023
+ }
2024
+ const version = ctx.str("version");
2025
+ if (version) assertValidSkillVersion(version);
2026
+ if (ctx.str("replaceSkillId") && !version) {
2027
+ throw new Error("--version is required with --replace-skill-id");
2028
+ }
2029
+ },
2030
+ dryRun: (ctx) => {
2031
+ const body = {
2032
+ file: ctx.str("file"),
2033
+ scope: ctx.str("scope") || "personal"
2034
+ };
2035
+ if (ctx.bool("autoRename")) body.autoRename = true;
2036
+ if (ctx.str("replaceSkillId")) body.replaceSkillId = ctx.str("replaceSkillId");
2037
+ if (ctx.str("category")) body.category = ctx.str("category");
2038
+ if (ctx.str("name")) body.name = ctx.str("name");
2039
+ if (ctx.str("displayName")) body.displayName = ctx.str("displayName");
2040
+ if (ctx.str("description")) body.description = ctx.str("description");
2041
+ if (ctx.str("instructions"))
2042
+ body.instructions = ctx.str("instructions") === "@-" ? "(from stdin)" : ctx.str("instructions");
2043
+ if (ctx.str("iconEmoji")) body.iconEmoji = ctx.str("iconEmoji");
2044
+ if (ctx.str("iconColor")) body.iconColor = ctx.str("iconColor");
2045
+ if (ctx.str("version")) body.version = ctx.str("version");
2046
+ return {
2047
+ method: "POST",
2048
+ url: `${BASE_PATH5}/upload`,
2049
+ body
2050
+ };
2051
+ },
2052
+ execute: async (ctx) => {
2053
+ const filePath = ctx.str("file");
2054
+ const resolved = resolve(filePath);
2055
+ const buffer = readFileSync(resolved);
2056
+ const fileName = basename(resolved);
2057
+ const fd = new FormData();
2058
+ const blob = new Blob([new Uint8Array(buffer)], {
2059
+ type: "application/zip"
2060
+ });
2061
+ fd.append("file", blob, fileName);
2062
+ const scope = ctx.str("scope") || "personal";
2063
+ fd.append("scope", scope);
2064
+ if (ctx.bool("autoRename")) fd.append("autoRename", "true");
2065
+ if (ctx.str("replaceSkillId")) fd.append("replaceSkillId", ctx.str("replaceSkillId"));
2066
+ if (ctx.str("category")) fd.append("category", ctx.str("category"));
2067
+ if (ctx.str("name")) fd.append("name", ctx.str("name"));
2068
+ if (ctx.str("displayName")) fd.append("displayName", ctx.str("displayName"));
2069
+ if (ctx.str("description")) fd.append("description", ctx.str("description"));
2070
+ if (ctx.str("instructions")) {
2071
+ const instructions = await resolveInstructions3(ctx.str("instructions"));
2072
+ fd.append("instructions", instructions);
2073
+ }
2074
+ if (ctx.str("iconEmoji")) fd.append("iconEmoji", ctx.str("iconEmoji"));
2075
+ if (ctx.str("iconColor")) fd.append("iconColor", ctx.str("iconColor"));
2076
+ if (ctx.str("version")) fd.append("version", ctx.str("version"));
2077
+ return uploadAgentApi(ctx, `${BASE_PATH5}/upload`, fd);
2078
+ }
2079
+ };
2080
+ var rescanSkills = {
2081
+ service: "agent",
2082
+ command: "+rescan-skills",
2083
+ description: "Rescan Skill files and sync to database (root only)",
2084
+ flags: [],
2085
+ risk: "write",
2086
+ dryRun: () => ({
2087
+ method: "POST",
2088
+ url: `${BASE_PATH5}/rescan`
2089
+ }),
2090
+ execute: async (ctx) => {
2091
+ return postAgentApi(ctx, `${BASE_PATH5}/rescan`, {});
2092
+ }
2093
+ };
2094
+
2095
+ // src/commands/te-agent/skill-approvals.ts
2096
+ var BASE = "/api/sandbox/agent/skills";
2097
+ var submitSkill = {
2098
+ service: "agent",
2099
+ command: "+submit-skill",
2100
+ description: "Submit a personal Skill for company-scope approval review",
2101
+ flags: [
2102
+ { name: "id", type: "string", required: true, desc: "Skill record ID (CUID, personal scope)" },
2103
+ { name: "description", type: "string", required: true, desc: "Submission reason / description (1-80 chars)" },
2104
+ { name: "category", type: "string", required: false, desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}` },
2105
+ { name: "icon-emoji", type: "string", required: false, desc: "Market icon emoji (e.g. robot)" },
2106
+ { name: "icon-color", type: "string", required: false, desc: "Market icon color (e.g. #1E76F0)" }
2107
+ ],
2108
+ risk: "write",
2109
+ validate: (ctx) => {
2110
+ const description = ctx.str("description");
2111
+ if (description.length < 1 || description.length > 80) {
2112
+ throw new Error("--description length must be between 1 and 80");
2113
+ }
2114
+ const category = ctx.str("category");
2115
+ if (category && !isValidMarketCategory(category)) {
2116
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
2117
+ }
2118
+ },
2119
+ dryRun: (ctx) => {
2120
+ const body = { description: ctx.str("description") };
2121
+ const category = ctx.str("category");
2122
+ if (category) body.category = category;
2123
+ const iconEmoji = ctx.str("iconEmoji");
2124
+ if (iconEmoji) body.iconEmoji = iconEmoji;
2125
+ const iconColor = ctx.str("iconColor");
2126
+ if (iconColor) body.iconColor = iconColor;
2127
+ return {
2128
+ method: "POST",
2129
+ url: `${BASE}/${encodeURIComponent(ctx.str("id"))}/submit`,
2130
+ body
2131
+ };
2132
+ },
2133
+ execute: async (ctx) => {
2134
+ const body = { description: ctx.str("description") };
2135
+ const category = ctx.str("category");
2136
+ if (category) body.category = category;
2137
+ const iconEmoji = ctx.str("iconEmoji");
2138
+ if (iconEmoji) body.iconEmoji = iconEmoji;
2139
+ const iconColor = ctx.str("iconColor");
2140
+ if (iconColor) body.iconColor = iconColor;
2141
+ return postAgentApi(ctx, `${BASE}/${encodeURIComponent(ctx.str("id"))}/submit`, body);
2142
+ }
2143
+ };
2144
+ var listSkillSubmissions = {
2145
+ service: "agent",
2146
+ command: "+list-skill-submissions",
2147
+ description: "List Skill submissions (approvals). Root sees all company submissions; others see only their own.",
2148
+ flags: [
2149
+ { name: "status", type: "string", required: false, desc: `Filter by status: ${SUBMISSION_STATUSES.join(" | ")}` },
2150
+ { name: "mine", type: "boolean", required: false, desc: "Only show submissions created by the current user (root only)" }
2151
+ ],
2152
+ risk: "read",
2153
+ validate: (ctx) => {
2154
+ const status = ctx.str("status");
2155
+ if (status && !SUBMISSION_STATUSES.includes(status)) {
2156
+ throw new Error(`--status must be one of: ${SUBMISSION_STATUSES.join(", ")}`);
2157
+ }
2158
+ },
2159
+ dryRun: (ctx) => {
2160
+ const params = new URLSearchParams();
2161
+ const status = ctx.str("status");
2162
+ if (status) params.set("status", status);
2163
+ if (ctx.bool("mine")) params.set("mine", "true");
2164
+ const qs = params.toString();
2165
+ return { method: "GET", url: `${BASE}/submissions${qs ? `?${qs}` : ""}` };
2166
+ },
2167
+ execute: async (ctx) => {
2168
+ const params = new URLSearchParams();
2169
+ const status = ctx.str("status");
2170
+ if (status) params.set("status", status);
2171
+ if (ctx.bool("mine")) params.set("mine", "true");
2172
+ const qs = params.toString();
2173
+ return getAgentApi(ctx, `${BASE}/submissions${qs ? `?${qs}` : ""}`);
2174
+ }
2175
+ };
2176
+ var cancelSkillSubmission = {
2177
+ service: "agent",
2178
+ command: "+cancel-skill-submission",
2179
+ description: "Cancel a pending Skill submission (submitter or root)",
2180
+ flags: [
2181
+ { name: "id", type: "string", required: true, desc: "Submission record ID (CUID)" }
2182
+ ],
2183
+ risk: "write",
2184
+ dryRun: (ctx) => ({
2185
+ method: "POST",
2186
+ url: `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/cancel`
2187
+ }),
2188
+ execute: async (ctx) => {
2189
+ return postAgentApi(ctx, `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/cancel`, {});
2190
+ }
2191
+ };
2192
+ var approveSkill = {
2193
+ service: "agent",
2194
+ command: "+approve-skill",
2195
+ description: "Approve a pending Skill submission (root only). Creates a company-scope copy.",
2196
+ flags: [
2197
+ { name: "id", type: "string", required: true, desc: "Submission record ID (CUID)" }
2198
+ ],
2199
+ risk: "write",
2200
+ dryRun: (ctx) => ({
2201
+ method: "POST",
2202
+ url: `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/approve`
2203
+ }),
2204
+ execute: async (ctx) => {
2205
+ return postAgentApi(ctx, `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/approve`, {});
2206
+ }
2207
+ };
2208
+ var rejectSkill = {
2209
+ service: "agent",
2210
+ command: "+reject-skill",
2211
+ description: "Reject a pending Skill submission with a reason (root only).",
2212
+ flags: [
2213
+ { name: "id", type: "string", required: true, desc: "Submission record ID (CUID)" },
2214
+ { name: "reason", type: "string", required: true, desc: "Rejection reason (1-80 chars)" }
2215
+ ],
2216
+ risk: "write",
2217
+ validate: (ctx) => {
2218
+ const reason = ctx.str("reason");
2219
+ if (reason.length < 1 || reason.length > 80) {
2220
+ throw new Error("--reason length must be between 1 and 80");
2221
+ }
2222
+ },
2223
+ dryRun: (ctx) => ({
2224
+ method: "POST",
2225
+ url: `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/reject`,
2226
+ body: { reason: ctx.str("reason") }
2227
+ }),
2228
+ execute: async (ctx) => {
2229
+ return postAgentApi(ctx, `${BASE}/submissions/${encodeURIComponent(ctx.str("id"))}/reject`, {
2230
+ reason: ctx.str("reason")
2231
+ });
2232
+ }
2233
+ };
2234
+
2235
+ // src/commands/te-agent/skill-shares.ts
2236
+ var BASE2 = "/api/sandbox/agent/skills";
2237
+ var shareSkill = {
2238
+ service: "agent",
2239
+ command: "+share-skill",
2240
+ description: "Share a personal Skill to another user in the same company",
2241
+ flags: [
2242
+ { name: "id", type: "string", required: true, desc: "Skill record ID (CUID, personal scope)" },
2243
+ { name: "to-user-id", type: "string", required: true, desc: "Recipient user ID (same company)" },
2244
+ { name: "category", type: "string", required: false, desc: `Market category key: ${MARKET_CATEGORIES.join(" | ")}` },
2245
+ { name: "icon-emoji", type: "string", required: false, desc: "Market icon emoji (e.g. robot)" },
2246
+ { name: "icon-color", type: "string", required: false, desc: "Market icon color (e.g. #1E76F0)" }
2247
+ ],
2248
+ risk: "write",
2249
+ validate: (ctx) => {
2250
+ const category = ctx.str("category");
2251
+ if (category && !isValidMarketCategory(category)) {
2252
+ throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
2253
+ }
2254
+ },
2255
+ dryRun: (ctx) => {
2256
+ const body = { toUserId: ctx.str("toUserId") };
2257
+ const category = ctx.str("category");
2258
+ if (category) body.category = category;
2259
+ const iconEmoji = ctx.str("iconEmoji");
2260
+ if (iconEmoji) body.iconEmoji = iconEmoji;
2261
+ const iconColor = ctx.str("iconColor");
2262
+ if (iconColor) body.iconColor = iconColor;
2263
+ return {
2264
+ method: "POST",
2265
+ url: `${BASE2}/${encodeURIComponent(ctx.str("id"))}/share`,
2266
+ body
2267
+ };
2268
+ },
2269
+ execute: async (ctx) => {
2270
+ const body = { toUserId: ctx.str("toUserId") };
2271
+ const category = ctx.str("category");
2272
+ if (category) body.category = category;
2273
+ const iconEmoji = ctx.str("iconEmoji");
2274
+ if (iconEmoji) body.iconEmoji = iconEmoji;
2275
+ const iconColor = ctx.str("iconColor");
2276
+ if (iconColor) body.iconColor = iconColor;
2277
+ return postAgentApi(ctx, `${BASE2}/${encodeURIComponent(ctx.str("id"))}/share`, body);
2278
+ }
2279
+ };
2280
+ var listSkillShares = {
2281
+ service: "agent",
2282
+ command: "+list-skill-shares",
2283
+ description: "List Skill shares (received by default; use --direction sent for outgoing)",
2284
+ flags: [
2285
+ { name: "direction", type: "string", required: false, default: "received", desc: `Direction: ${SHARE_DIRECTIONS.join(" | ")}` },
2286
+ { name: "status", type: "string", required: false, desc: `Filter by status: ${SHARE_STATUSES.join(" | ")}` }
2287
+ ],
2288
+ risk: "read",
2289
+ validate: (ctx) => {
2290
+ const direction = ctx.str("direction");
2291
+ if (direction && !SHARE_DIRECTIONS.includes(direction)) {
2292
+ throw new Error(`--direction must be one of: ${SHARE_DIRECTIONS.join(", ")}`);
2293
+ }
2294
+ const status = ctx.str("status");
2295
+ if (status && !SHARE_STATUSES.includes(status)) {
2296
+ throw new Error(`--status must be one of: ${SHARE_STATUSES.join(", ")}`);
2297
+ }
2298
+ },
2299
+ dryRun: (ctx) => {
2300
+ const params = new URLSearchParams();
2301
+ params.set("direction", ctx.str("direction") || "received");
2302
+ const status = ctx.str("status");
2303
+ if (status) params.set("status", status);
2304
+ return { method: "GET", url: `${BASE2}/shares?${params.toString()}` };
2305
+ },
2306
+ execute: async (ctx) => {
2307
+ const params = new URLSearchParams();
2308
+ params.set("direction", ctx.str("direction") || "received");
2309
+ const status = ctx.str("status");
2310
+ if (status) params.set("status", status);
2311
+ return getAgentApi(ctx, `${BASE2}/shares?${params.toString()}`);
2312
+ }
2313
+ };
2314
+ var acceptSkillShare = {
2315
+ service: "agent",
2316
+ command: "+accept-skill-share",
2317
+ description: "Accept a received Skill share (creates a personal copy for the recipient)",
2318
+ flags: [
2319
+ { name: "id", type: "string", required: true, desc: "Share record ID (CUID)" }
2320
+ ],
2321
+ risk: "write",
2322
+ dryRun: (ctx) => ({
2323
+ method: "POST",
2324
+ url: `${BASE2}/shares/${encodeURIComponent(ctx.str("id"))}/accept`
2325
+ }),
2326
+ execute: async (ctx) => {
2327
+ return postAgentApi(ctx, `${BASE2}/shares/${encodeURIComponent(ctx.str("id"))}/accept`, {});
2328
+ }
2329
+ };
2330
+ var rejectSkillShare = {
2331
+ service: "agent",
2332
+ command: "+reject-skill-share",
2333
+ description: "Reject a received Skill share",
2334
+ flags: [
2335
+ { name: "id", type: "string", required: true, desc: "Share record ID (CUID)" }
2336
+ ],
2337
+ risk: "write",
2338
+ dryRun: (ctx) => ({
2339
+ method: "POST",
2340
+ url: `${BASE2}/shares/${encodeURIComponent(ctx.str("id"))}/reject`
2341
+ }),
2342
+ execute: async (ctx) => {
2343
+ return postAgentApi(ctx, `${BASE2}/shares/${encodeURIComponent(ctx.str("id"))}/reject`, {});
2344
+ }
2345
+ };
2346
+
2347
+ // src/commands/te-agent/attachments.ts
2348
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
2349
+ import { resolve as resolve2, basename as basename2, extname as extname2 } from "path";
2350
+ var LIST_PATH = "/api/sandbox/agent/attachments";
2351
+ var UPLOAD_PATH = "/api/sandbox/agent/attachments/upload";
2352
+ var STATS_PATH2 = "/api/sandbox/agent/attachments/stats";
2353
+ function guessMimeType2(filePath) {
2354
+ const ext = extname2(filePath).toLowerCase();
2355
+ const map = {
2356
+ ".png": "image/png",
2357
+ ".jpg": "image/jpeg",
2358
+ ".jpeg": "image/jpeg",
2359
+ ".gif": "image/gif",
2360
+ ".webp": "image/webp",
2361
+ ".svg": "image/svg+xml",
2362
+ ".pdf": "application/pdf",
2363
+ ".md": "text/markdown",
2364
+ ".txt": "text/plain",
2365
+ ".csv": "text/csv",
2366
+ ".json": "application/json",
2367
+ ".html": "text/html",
2368
+ ".xml": "application/xml",
2369
+ ".doc": "application/msword",
2370
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2371
+ ".xls": "application/vnd.ms-excel",
2372
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
2373
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
2374
+ ".zip": "application/zip"
2375
+ };
2376
+ return map[ext] || "application/octet-stream";
2377
+ }
2378
+ function resolveFilePaths(ctx) {
2379
+ const file = ctx.str("file");
2380
+ const files = ctx.str("files");
2381
+ if (file && files) {
2382
+ throw new Error("--file and --files cannot be used together");
2383
+ }
2384
+ if (!file && !files) {
2385
+ throw new Error("Either --file or --files must be specified");
2386
+ }
2387
+ if (file) return [file];
2388
+ try {
2389
+ const parsed = JSON.parse(files);
2390
+ if (!Array.isArray(parsed)) throw new Error("--files must be a JSON array");
2391
+ return parsed.map((p) => {
2392
+ if (typeof p !== "string") throw new Error("--files array elements must be strings");
2393
+ return p;
2394
+ });
2395
+ } catch (err) {
2396
+ if (err instanceof SyntaxError) throw new Error("--files must be a valid JSON array");
2397
+ throw err;
2398
+ }
2399
+ }
2400
+ async function uploadFiles(ctx, filePaths) {
2401
+ const formData = new FormData();
2402
+ for (const filePath of filePaths) {
2403
+ const resolved = resolve2(filePath);
2404
+ if (!existsSync2(resolved)) {
2405
+ throw new Error(`File not found: ${resolved}`);
2406
+ }
2407
+ const buffer = readFileSync2(resolved);
2408
+ const mimeType = guessMimeType2(resolved);
2409
+ const blob = new Blob([buffer], { type: mimeType });
2410
+ formData.append("file", blob, basename2(resolved));
2411
+ }
2412
+ return uploadAgentApi(ctx, UPLOAD_PATH, formData);
2413
+ }
2414
+ var listAttachments = {
2415
+ service: "agent",
2416
+ command: "+list-attachments",
2417
+ description: "List user attachments (paginated)",
2418
+ flags: [
2419
+ { name: "q", type: "string", required: false, desc: "Search keyword" },
2420
+ { name: "type", type: "string", required: false, desc: "Filter by type: image | document" },
2421
+ { name: "page", type: "number", required: false, desc: "Page number (default 1)" },
2422
+ { name: "page-size", type: "number", required: false, desc: "Page size (default 20, max 10000)" }
2423
+ ],
2424
+ risk: "read",
2425
+ validate: (ctx) => {
2426
+ const type = ctx.str("type");
2427
+ if (type && !["image", "document"].includes(type)) {
2428
+ throw new Error("--type must be image or document");
2429
+ }
2430
+ },
2431
+ dryRun: (ctx) => {
2432
+ const params = new URLSearchParams();
2433
+ if (ctx.str("q")) params.set("q", ctx.str("q"));
2434
+ if (ctx.str("type")) params.set("type", ctx.str("type"));
2435
+ if (ctx.num("page")) params.set("page", String(ctx.num("page")));
2436
+ if (ctx.num("pageSize")) params.set("pageSize", String(ctx.num("pageSize")));
2437
+ const qs = params.toString();
2438
+ return { method: "GET", url: `${LIST_PATH}${qs ? "?" + qs : ""}` };
2439
+ },
2440
+ execute: async (ctx) => {
2441
+ const params = new URLSearchParams();
2442
+ if (ctx.str("q")) params.set("q", ctx.str("q"));
2443
+ if (ctx.str("type")) params.set("type", ctx.str("type"));
2444
+ if (ctx.num("page")) params.set("page", String(ctx.num("page")));
2445
+ if (ctx.num("pageSize")) params.set("pageSize", String(ctx.num("pageSize")));
2446
+ const qs = params.toString();
2447
+ return getAgentApi(ctx, `${LIST_PATH}${qs ? "?" + qs : ""}`);
2448
+ }
2449
+ };
2450
+ var addAttachment = {
2451
+ service: "agent",
2452
+ command: "+add-attachment",
2453
+ description: "Upload sandbox file(s) to attachment library",
2454
+ flags: [
2455
+ { name: "file", type: "string", required: false, desc: "Single file path" },
2456
+ { name: "files", type: "string", required: false, desc: `JSON array of file paths, e.g. '["./a.png","./b.pdf"]'` }
2457
+ ],
2458
+ risk: "write",
2459
+ validate: (ctx) => {
2460
+ resolveFilePaths(ctx);
2461
+ },
2462
+ dryRun: (ctx) => {
2463
+ const paths = resolveFilePaths(ctx);
2464
+ return { method: "POST", url: UPLOAD_PATH, body: { files: paths } };
2465
+ },
2466
+ execute: async (ctx) => {
2467
+ const paths = resolveFilePaths(ctx);
2468
+ return uploadFiles(ctx, paths);
2469
+ }
2470
+ };
2471
+ var delAttachment = {
2472
+ service: "agent",
2473
+ command: "+del-attachment",
2474
+ description: "Soft-delete an attachment",
2475
+ flags: [
2476
+ { name: "id", type: "string", required: true, desc: "Attachment ID" }
2477
+ ],
2478
+ risk: "high-risk-write",
2479
+ dryRun: (ctx) => ({
2480
+ method: "DELETE",
2481
+ url: `${LIST_PATH}?id=${encodeURIComponent(ctx.str("id"))}`
2482
+ }),
2483
+ execute: async (ctx) => {
2484
+ return deleteAgentApi(ctx, `${LIST_PATH}?id=${encodeURIComponent(ctx.str("id"))}`);
2485
+ }
2486
+ };
2487
+ var attachmentStats = {
2488
+ service: "agent",
2489
+ command: "+attachment-stats",
2490
+ description: "Show attachment library statistics (total files, size, images, documents)",
2491
+ flags: [],
2492
+ risk: "read",
2493
+ dryRun: () => ({
2494
+ method: "GET",
2495
+ url: STATS_PATH2
2496
+ }),
2497
+ execute: async (ctx) => {
2498
+ return getAgentApi(ctx, STATS_PATH2);
2499
+ }
2500
+ };
2501
+
2502
+ // src/commands/te-agent/automations.ts
2503
+ var BASE_PATH6 = "/api/sandbox/agent/automations";
2504
+ var SCHEDULE_KINDS = ["hourly", "daily", "weekly", "monthly"];
2505
+ var TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)$/;
2506
+ var AUTOMATION_STATUSES = ["active", "paused"];
2507
+ function optional(value) {
2508
+ const trimmed = value.trim();
2509
+ return trimmed ? trimmed : void 0;
2510
+ }
2511
+ function envOptional(name) {
2512
+ return optional(process.env[name] ?? "");
2513
+ }
2514
+ function readEnabled(ctx) {
2515
+ return readEnabledOptional(ctx) ?? true;
2516
+ }
2517
+ function readEnabledOptional(ctx) {
2518
+ const enabled = ctx.json("enabled");
2519
+ if (enabled === void 0) return void 0;
2520
+ if (typeof enabled !== "boolean") {
2521
+ throw new Error("--enabled \u5FC5\u987B\u662F true \u6216 false");
2522
+ }
2523
+ return enabled;
2524
+ }
2525
+ function readReuseConversation(ctx) {
2526
+ return readReuseConversationOptional(ctx) ?? false;
2527
+ }
2528
+ function readReuseConversationOptional(ctx) {
2529
+ const reuseConversation = ctx.json("reuseConversation");
2530
+ if (reuseConversation === void 0) return void 0;
2531
+ if (typeof reuseConversation !== "boolean") {
2532
+ throw new Error("--reuse-conversation must be true or false");
2533
+ }
2534
+ return reuseConversation;
2535
+ }
2536
+ function buildSchedule(ctx) {
2537
+ const kind = optional(ctx.str("scheduleKind"));
2538
+ if (!kind) return void 0;
2539
+ if (kind === "hourly") {
2540
+ const minute = ctx.str("minute") ? ctx.num("minute") : void 0;
2541
+ return { kind, ...minute === void 0 ? {} : { minute } };
2542
+ }
2543
+ if (kind === "daily") return { kind, time: ctx.str("time") };
2544
+ if (kind === "weekly") {
2545
+ return { kind, time: ctx.str("time"), weekday: ctx.num("weekday") };
2546
+ }
2547
+ return {
2548
+ kind: "monthly",
2549
+ time: ctx.str("time"),
2550
+ dayOfMonth: ctx.num("dayOfMonth")
2551
+ };
2552
+ }
2553
+ function hasScheduleDetail(ctx) {
2554
+ return Boolean(
2555
+ optional(ctx.str("time")) || optional(ctx.str("minute")) || optional(ctx.str("weekday")) || optional(ctx.str("dayOfMonth"))
2556
+ );
2557
+ }
2558
+ function validateSchedule(ctx, required) {
2559
+ const cron = optional(ctx.str("cron"));
2560
+ const kind = optional(ctx.str("scheduleKind"));
2561
+ if (cron && kind) {
2562
+ throw new Error("--cron \u4E0E --schedule-kind \u53EA\u80FD\u4E8C\u9009\u4E00");
2563
+ }
2564
+ if (!cron && !kind) {
2565
+ if (required || hasScheduleDetail(ctx)) {
2566
+ throw new Error("\u5FC5\u987B\u63D0\u4F9B --cron \u6216 --schedule-kind");
2567
+ }
2568
+ return;
2569
+ }
2570
+ if (!kind) return;
2571
+ if (!SCHEDULE_KINDS.includes(kind)) {
2572
+ throw new Error("--schedule-kind \u5FC5\u987B\u662F hourly\u3001daily\u3001weekly \u6216 monthly");
2573
+ }
2574
+ const time = optional(ctx.str("time"));
2575
+ if (kind !== "hourly") {
2576
+ if (!time) throw new Error(`${kind} \u8C03\u5EA6\u5FC5\u987B\u63D0\u4F9B --time HH:mm`);
2577
+ if (!TIME_RE.test(time)) throw new Error("--time \u683C\u5F0F\u5FC5\u987B\u662F HH:mm");
2578
+ }
2579
+ if (kind === "hourly" && ctx.str("minute")) {
2580
+ const minute = ctx.num("minute");
2581
+ if (!Number.isInteger(minute) || minute < 0 || minute > 59) {
2582
+ throw new Error("--minute \u5FC5\u987B\u662F 0-59 \u7684\u6574\u6570");
2583
+ }
2584
+ }
2585
+ if (kind === "weekly") {
2586
+ const weekday = ctx.num("weekday");
2587
+ if (!Number.isInteger(weekday) || weekday < 0 || weekday > 6) {
2588
+ throw new Error("--weekday \u5FC5\u987B\u662F 0-6 \u7684\u6574\u6570\uFF0C0 \u8868\u793A\u5468\u65E5");
2589
+ }
2590
+ }
2591
+ if (kind === "monthly") {
2592
+ const dayOfMonth = ctx.num("dayOfMonth");
2593
+ if (!Number.isInteger(dayOfMonth) || dayOfMonth < 1 || dayOfMonth > 28) {
2594
+ throw new Error("--day-of-month \u5FC5\u987B\u662F 1-28 \u7684\u6574\u6570");
2595
+ }
2596
+ }
2597
+ }
2598
+ function buildCreateBody(ctx) {
2599
+ const explicitAgentId = optional(ctx.str("agentId"));
2600
+ const explicitAgentName = optional(ctx.str("agentName"));
2601
+ const agentId = explicitAgentId ?? (explicitAgentName ? void 0 : envOptional("TE_AGENT_CURRENT_AGENT_ID"));
2602
+ const conversationId = optional(ctx.str("conversationId")) ?? envOptional("TE_AGENT_CONVERSATION_ID");
2603
+ const model = optional(ctx.str("model")) ?? envOptional("TE_AGENT_CURRENT_MODEL_ID");
2604
+ const enabled = readEnabled(ctx);
2605
+ return {
2606
+ name: ctx.str("name"),
2607
+ message: ctx.str("message"),
2608
+ agentId,
2609
+ agentName: explicitAgentName,
2610
+ conversationId,
2611
+ cronExpression: optional(ctx.str("cron")),
2612
+ schedule: buildSchedule(ctx),
2613
+ triggerType: "scheduled",
2614
+ model,
2615
+ reuseConversation: readReuseConversation(ctx),
2616
+ status: enabled ? "active" : "paused"
2617
+ };
2618
+ }
2619
+ function buildListPath(ctx) {
2620
+ const params = new URLSearchParams();
2621
+ const q = optional(ctx.str("q"));
2622
+ const status = optional(ctx.str("status"));
2623
+ const limit = optional(ctx.str("limit"));
2624
+ if (q) params.set("q", q);
2625
+ if (status) params.set("status", status);
2626
+ if (limit) params.set("limit", String(ctx.num("limit")));
2627
+ const query = params.toString();
2628
+ return query ? `${BASE_PATH6}?${query}` : BASE_PATH6;
2629
+ }
2630
+ function validateList(ctx) {
2631
+ const status = optional(ctx.str("status"));
2632
+ if (status && !AUTOMATION_STATUSES.includes(status)) {
2633
+ throw new Error("--status \u5FC5\u987B\u662F active \u6216 paused");
2634
+ }
2635
+ if (ctx.str("limit")) {
2636
+ const limit = ctx.num("limit");
2637
+ if (!Number.isInteger(limit) || limit < 1 || limit > 50) {
2638
+ throw new Error("--limit \u5FC5\u987B\u662F 1-10000 \u7684\u6574\u6570");
2639
+ }
2640
+ }
2641
+ }
2642
+ function buildUpdateBody2(ctx) {
2643
+ const enabled = readEnabledOptional(ctx);
2644
+ const reuseConversation = readReuseConversationOptional(ctx);
2645
+ const body = {};
2646
+ const name = optional(ctx.str("name"));
2647
+ const message = optional(ctx.str("message"));
2648
+ const cron = optional(ctx.str("cron"));
2649
+ const schedule = buildSchedule(ctx);
2650
+ if (name) body.name = name;
2651
+ if (message !== void 0) body.message = message;
2652
+ if (enabled !== void 0) body.status = enabled ? "active" : "paused";
2653
+ if (reuseConversation !== void 0)
2654
+ body.reuseConversation = reuseConversation;
2655
+ if (cron) body.cronExpression = cron;
2656
+ if (schedule) body.schedule = schedule;
2657
+ return body;
2658
+ }
2659
+ function validateUpdate(ctx) {
2660
+ validateSchedule(ctx, false);
2661
+ if (!Object.keys(buildUpdateBody2(ctx)).length) {
2662
+ throw new Error("\u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A\u66F4\u65B0\u5B57\u6BB5");
2663
+ }
2664
+ }
2665
+ var scheduleFlags = [
2666
+ {
2667
+ name: "cron",
2668
+ type: "string",
2669
+ required: false,
2670
+ desc: "Cron expression for supported hourly/daily/weekly/monthly schedules"
2671
+ },
2672
+ {
2673
+ name: "schedule-kind",
2674
+ type: "string",
2675
+ required: false,
2676
+ desc: "hourly | daily | weekly | monthly"
2677
+ },
2678
+ {
2679
+ name: "time",
2680
+ type: "string",
2681
+ required: false,
2682
+ desc: "Time in HH:mm for daily/weekly/monthly"
2683
+ },
2684
+ {
2685
+ name: "minute",
2686
+ type: "number",
2687
+ required: false,
2688
+ desc: "Minute 0-59 for hourly schedules"
2689
+ },
2690
+ {
2691
+ name: "weekday",
2692
+ type: "number",
2693
+ required: false,
2694
+ desc: "Weekday 0-6 for weekly schedules; 0 is Sunday"
2695
+ },
2696
+ {
2697
+ name: "day-of-month",
2698
+ type: "number",
2699
+ required: false,
2700
+ desc: "Day 1-28 for monthly schedules"
2701
+ }
2702
+ ];
2703
+ var listAutomations = {
2704
+ service: "agent",
2705
+ command: "+list-automations",
2706
+ description: "List current user's Agent automation tasks",
2707
+ flags: [
2708
+ {
2709
+ name: "q",
2710
+ type: "string",
2711
+ required: false,
2712
+ desc: "Keyword for automation name or instruction"
2713
+ },
2714
+ {
2715
+ name: "status",
2716
+ type: "string",
2717
+ required: false,
2718
+ desc: "active | paused"
2719
+ },
2720
+ {
2721
+ name: "limit",
2722
+ type: "number",
2723
+ required: false,
2724
+ desc: "Maximum number of automations to return, 1-10000"
2725
+ }
2726
+ ],
2727
+ risk: "read",
2728
+ validate: validateList,
2729
+ dryRun: (ctx) => ({
2730
+ method: "GET",
2731
+ url: buildListPath(ctx)
2732
+ }),
2733
+ execute: async (ctx) => getAgentApi(ctx, buildListPath(ctx))
2734
+ };
2735
+ var createAutomation = {
2736
+ service: "agent",
2737
+ command: "+create-automation",
2738
+ description: "Create an Agent automation task",
2739
+ flags: [
2740
+ {
2741
+ name: "name",
2742
+ type: "string",
2743
+ required: true,
2744
+ desc: "Automation task name"
2745
+ },
2746
+ {
2747
+ name: "message",
2748
+ type: "string",
2749
+ required: true,
2750
+ desc: "Instruction sent to the Agent"
2751
+ },
2752
+ {
2753
+ name: "agent-id",
2754
+ type: "string",
2755
+ required: false,
2756
+ desc: "Agent ID; defaults to current conversation Agent"
2757
+ },
2758
+ {
2759
+ name: "agent-name",
2760
+ type: "string",
2761
+ required: false,
2762
+ desc: "Agent name; use only after +list-agents discovery"
2763
+ },
2764
+ {
2765
+ name: "model",
2766
+ type: "string",
2767
+ required: false,
2768
+ desc: "Model record ID; defaults to current selected model"
2769
+ },
2770
+ {
2771
+ name: "enabled",
2772
+ type: "boolean",
2773
+ required: false,
2774
+ desc: "Whether to enable the automation immediately; defaults to true"
2775
+ },
2776
+ {
2777
+ name: "reuse-conversation",
2778
+ type: "boolean",
2779
+ required: false,
2780
+ desc: "Continue future runs in the same conversation; defaults to false"
2781
+ },
2782
+ {
2783
+ name: "conversation-id",
2784
+ type: "string",
2785
+ required: false,
2786
+ desc: "Conversation ID fallback for resolving current Agent"
2787
+ },
2788
+ ...scheduleFlags
2789
+ ],
2790
+ risk: "write",
2791
+ validate: (ctx) => {
2792
+ if (ctx.str("agentId") && ctx.str("agentName")) {
2793
+ throw new Error("--agent-id \u4E0E --agent-name \u53EA\u80FD\u4E8C\u9009\u4E00");
2794
+ }
2795
+ validateSchedule(ctx, true);
2796
+ },
2797
+ dryRun: (ctx) => ({
2798
+ method: "POST",
2799
+ url: BASE_PATH6,
2800
+ body: buildCreateBody(ctx)
2801
+ }),
2802
+ execute: async (ctx) => postAgentApi(ctx, BASE_PATH6, buildCreateBody(ctx))
2803
+ };
2804
+ var updateAutomation = {
2805
+ service: "agent",
2806
+ command: "+update-automation",
2807
+ description: "Update an Agent automation task",
2808
+ flags: [
2809
+ {
2810
+ name: "id",
2811
+ type: "string",
2812
+ required: true,
2813
+ desc: "Automation task ID from +list-automations"
2814
+ },
2815
+ {
2816
+ name: "name",
2817
+ type: "string",
2818
+ required: false,
2819
+ desc: "New automation task name"
2820
+ },
2821
+ {
2822
+ name: "message",
2823
+ type: "string",
2824
+ required: false,
2825
+ desc: "New instruction sent to the Agent"
2826
+ },
2827
+ {
2828
+ name: "enabled",
2829
+ type: "boolean",
2830
+ required: false,
2831
+ desc: "true to enable, false to pause"
2832
+ },
2833
+ {
2834
+ name: "reuse-conversation",
2835
+ type: "boolean",
2836
+ required: false,
2837
+ desc: "true to reuse one conversation, false to create one per run"
2838
+ },
2839
+ ...scheduleFlags
2840
+ ],
2841
+ risk: "write",
2842
+ validate: validateUpdate,
2843
+ dryRun: (ctx) => ({
2844
+ method: "PATCH",
2845
+ url: `${BASE_PATH6}/${encodeURIComponent(ctx.str("id"))}`,
2846
+ body: buildUpdateBody2(ctx)
2847
+ }),
2848
+ execute: async (ctx) => patchAgentApi(
2849
+ ctx,
2850
+ `${BASE_PATH6}/${encodeURIComponent(ctx.str("id"))}`,
2851
+ buildUpdateBody2(ctx)
2852
+ )
2853
+ };
2854
+
2855
+ // src/commands/te-agent/sandbox-tools.ts
2856
+ import {
2857
+ accessSync,
2858
+ closeSync,
2859
+ constants,
2860
+ existsSync as existsSync3,
2861
+ lstatSync,
2862
+ openSync,
2863
+ readSync,
2864
+ readdirSync,
2865
+ realpathSync
2866
+ } from "fs";
2867
+ import { isAbsolute, join, relative, resolve as resolve3 } from "path";
2868
+ var SANDBOX_BIN_DIR = "/home/ta/.local/bin";
2869
+ var SANDBOX_SHARE_ROOT = process.env.SANDBOX_SYSTEM_SHARE_ROOT ?? "/data/app/te_agent_ta/share";
2870
+ var SHIM_MARKER = "managed-by: te-agent-sandbox-tools";
2871
+ var MAX_SHIM_BYTES = 16 * 1024;
2872
+ var NAME_RE = /^[a-z][a-z0-9._-]{0,63}$/;
2873
+ function hasControlCharacters(value) {
2874
+ return /[\x00-\x1f\x7f]/.test(value);
2875
+ }
2876
+ function readShimHeader(filePath, size) {
2877
+ const buffer = Buffer.alloc(Math.min(size, MAX_SHIM_BYTES));
2878
+ const fd = openSync(filePath, "r");
2879
+ try {
2880
+ const bytesRead = readSync(fd, buffer, 0, buffer.length, 0);
2881
+ return buffer.toString("utf8", 0, bytesRead);
2882
+ } finally {
2883
+ closeSync(fd);
2884
+ }
2885
+ }
2886
+ function parseShim(filePath) {
2887
+ const fallback = {
2888
+ managed: false,
2889
+ tool: "",
2890
+ version: "unknown",
2891
+ command: "",
2892
+ target: ""
2893
+ };
2894
+ try {
2895
+ const stat = lstatSync(filePath);
2896
+ if (!stat.isFile() || stat.isSymbolicLink()) return fallback;
2897
+ const lines = readShimHeader(filePath, stat.size).split("\n").slice(0, 10);
2898
+ const managed = lines.includes(`# ${SHIM_MARKER}`);
2899
+ if (!managed) return fallback;
2900
+ if (stat.size > MAX_SHIM_BYTES) {
2901
+ return { ...fallback, managed: true, reason: "shim exceeds size limit" };
2902
+ }
2903
+ const values = /* @__PURE__ */ new Map();
2904
+ for (const line of lines) {
2905
+ if (line === `# ${SHIM_MARKER}`) continue;
2906
+ const match = /^# (tool|version|command|target|runtime): (.*)$/.exec(
2907
+ line
2908
+ );
2909
+ if (!match) continue;
2910
+ if (values.has(match[1])) {
2911
+ return { ...fallback, managed, reason: `duplicate ${match[1]} marker` };
2912
+ }
2913
+ values.set(match[1], match[2].trim());
2914
+ }
2915
+ const tool = values.get("tool") ?? "";
2916
+ const version = values.get("version") || "unknown";
2917
+ const command = values.get("command") ?? "";
2918
+ const target = values.get("target") ?? "";
2919
+ const runtimeValue = values.get("runtime");
2920
+ const runtime = runtimeValue === "node" || runtimeValue === "native" ? runtimeValue : void 0;
2921
+ if (!NAME_RE.test(tool) || !NAME_RE.test(command)) {
2922
+ return {
2923
+ ...fallback,
2924
+ managed: true,
2925
+ reason: "invalid tool or command marker"
2926
+ };
2927
+ }
2928
+ if (version.length > 64 || hasControlCharacters(version) || hasControlCharacters(target) || !isAbsolute(target)) {
2929
+ return {
2930
+ ...fallback,
2931
+ managed: true,
2932
+ tool,
2933
+ command,
2934
+ reason: "invalid version or target marker"
2935
+ };
2936
+ }
2937
+ if (runtimeValue && !runtime) {
2938
+ return {
2939
+ ...fallback,
2940
+ managed: true,
2941
+ tool,
2942
+ version,
2943
+ command,
2944
+ target,
2945
+ reason: "invalid runtime marker"
2946
+ };
2947
+ }
2948
+ return { managed: true, tool, version, command, target, runtime };
2949
+ } catch {
2950
+ return fallback;
2951
+ }
2952
+ }
2953
+ function isInsideOrEqual(candidate, root) {
2954
+ const rel = relative(root, candidate);
2955
+ return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
2956
+ }
2957
+ function classifyShim(parsed, toolsRoot) {
2958
+ if (parsed.reason) return { status: "broken", reason: parsed.reason };
2959
+ if (!parsed.target)
2960
+ return { status: "broken", reason: "shim missing target marker" };
2961
+ let realRoot;
2962
+ try {
2963
+ realRoot = realpathSync(resolve3(toolsRoot));
2964
+ } catch {
2965
+ return { status: "broken", reason: "tools root missing" };
2966
+ }
2967
+ let realTarget;
2968
+ try {
2969
+ realTarget = realpathSync(parsed.target);
2970
+ } catch {
2971
+ return { status: "broken", reason: "target missing" };
2972
+ }
2973
+ if (!isInsideOrEqual(realTarget, realRoot)) {
2974
+ return { status: "broken", reason: "target outside tools root" };
2975
+ }
2976
+ try {
2977
+ if (!lstatSync(realTarget).isFile()) {
2978
+ return { status: "broken", reason: "target not a file" };
2979
+ }
2980
+ accessSync(
2981
+ realTarget,
2982
+ parsed.runtime === "native" ? constants.X_OK : constants.R_OK
2983
+ );
2984
+ } catch {
2985
+ return {
2986
+ status: "broken",
2987
+ reason: parsed.runtime === "native" ? "target not executable" : "target not readable"
2988
+ };
2989
+ }
2990
+ return { status: "active" };
2991
+ }
2992
+ function scanSandboxTools(options = {}) {
2993
+ const binDir = options.binDir ?? SANDBOX_BIN_DIR;
2994
+ const toolsRoot = options.toolsRoot ?? join(SANDBOX_SHARE_ROOT, "tools");
2995
+ if (!existsSync3(binDir)) {
2996
+ return { tools: [], summary: { total: 0, active: 0, broken: 0 } };
2997
+ }
2998
+ const all = [];
2999
+ for (const name of readdirSync(binDir).sort()) {
3000
+ const filePath = join(binDir, name);
3001
+ const parsed = parseShim(filePath);
3002
+ if (!parsed.managed) continue;
3003
+ const { status, reason } = classifyShim(parsed, toolsRoot);
3004
+ all.push({
3005
+ tool: parsed.tool || "unknown",
3006
+ version: parsed.version || "unknown",
3007
+ command: parsed.command || name,
3008
+ runtime: parsed.runtime ?? "unknown",
3009
+ target: parsed.target,
3010
+ status,
3011
+ reason
3012
+ });
3013
+ }
3014
+ const active = all.filter((entry) => entry.status === "active").length;
3015
+ const broken = all.filter((entry) => entry.status === "broken").length;
3016
+ const tools = options.status ? all.filter((entry) => entry.status === options.status) : all;
3017
+ return { tools, summary: { total: all.length, active, broken } };
3018
+ }
3019
+ var listSandboxTools = {
3020
+ service: "agent",
3021
+ command: "+list-sandbox-tools",
3022
+ description: "List managed tools in the current sandbox and verify their targets and permissions",
3023
+ flags: [
3024
+ {
3025
+ name: "status",
3026
+ type: "string",
3027
+ required: false,
3028
+ desc: "Filter by status: active | broken"
3029
+ }
3030
+ ],
3031
+ risk: "read",
3032
+ validate: (ctx) => {
3033
+ const status = ctx.str("status");
3034
+ if (status && !["active", "broken"].includes(status)) {
3035
+ throw new Error("--status must be active or broken");
3036
+ }
3037
+ },
3038
+ dryRun: () => ({
3039
+ method: "LOCAL_SCAN",
3040
+ url: SANDBOX_BIN_DIR,
3041
+ body: { marker: SHIM_MARKER, toolsRoot: join(SANDBOX_SHARE_ROOT, "tools") }
3042
+ }),
3043
+ execute: async (ctx) => scanSandboxTools({ status: ctx.str("status") })
3044
+ };
3045
+
3046
+ // src/commands/te-agent/conversations.ts
3047
+ var CONVERSATION_PATH = "/api/sandbox/agent/conversations";
3048
+ var ARCHIVE_SEARCH_PATH = `${CONVERSATION_PATH}/archived`;
3049
+ var DEFAULT_LIMIT = 20;
3050
+ var DEFAULT_TIME_ZONE = "Asia/Shanghai";
3051
+ function optional2(value) {
3052
+ const trimmed = value.trim();
3053
+ return trimmed ? trimmed : void 0;
3054
+ }
3055
+ function envOptional2(name) {
3056
+ return optional2(process.env[name] ?? "");
3057
+ }
3058
+ function readAll(ctx) {
3059
+ return ctx.str("all") === "true";
3060
+ }
3061
+ function readTimeZone(ctx) {
3062
+ return optional2(ctx.str("timeZone")) ?? DEFAULT_TIME_ZONE;
3063
+ }
3064
+ function isValidTimeZone(timeZone) {
3065
+ try {
3066
+ new Intl.DateTimeFormat("en-US", { timeZone }).format();
3067
+ return true;
3068
+ } catch {
3069
+ return false;
3070
+ }
3071
+ }
3072
+ function formatTimestampInTimeZone(timestamp, timeZone) {
3073
+ const parts = new Intl.DateTimeFormat("en-CA", {
3074
+ timeZone,
3075
+ calendar: "gregory",
3076
+ numberingSystem: "latn",
3077
+ year: "numeric",
3078
+ month: "2-digit",
3079
+ day: "2-digit",
3080
+ hour: "2-digit",
3081
+ minute: "2-digit",
3082
+ second: "2-digit",
3083
+ hourCycle: "h23"
3084
+ }).formatToParts(new Date(timestamp));
3085
+ const values = Object.fromEntries(
3086
+ parts.map(({ type, value }) => [type, value])
3087
+ );
3088
+ return `${values.year}-${values.month}-${values.day} ${values.hour}:${values.minute}:${values.second}`;
3089
+ }
3090
+ function validateFind(ctx) {
3091
+ const rawAll = ctx.str("all");
3092
+ if (rawAll && rawAll !== "true" && rawAll !== "false") return;
3093
+ const agentId = optional2(ctx.str("agentId"));
3094
+ const all = readAll(ctx);
3095
+ if (agentId && all) {
3096
+ throw new Error("--agent-id and --all true cannot be used together");
3097
+ }
3098
+ if (!agentId && !all && !envOptional2("TE_AGENT_CURRENT_AGENT_ID")) {
3099
+ throw new Error(
3100
+ "Archive scope is required. Provide --agent-id or --all true, or run inside an Agent sandbox."
3101
+ );
3102
+ }
3103
+ const limit = optional2(ctx.str("limit")) ? ctx.num("limit") : DEFAULT_LIMIT;
3104
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
3105
+ throw new Error("--limit must be an integer between 1 and 100");
3106
+ }
3107
+ if (!isValidTimeZone(readTimeZone(ctx))) {
3108
+ throw new Error("--time-zone must be a valid IANA time zone");
3109
+ }
3110
+ }
3111
+ function buildArchivedConversationSearchPath(ctx) {
3112
+ const params = new URLSearchParams();
3113
+ const q = optional2(ctx.str("q"));
3114
+ const explicitAgentId = optional2(ctx.str("agentId"));
3115
+ const all = readAll(ctx);
3116
+ const agentId = explicitAgentId ?? envOptional2("TE_AGENT_CURRENT_AGENT_ID");
3117
+ const limit = optional2(ctx.str("limit")) ? ctx.num("limit") : DEFAULT_LIMIT;
3118
+ if (q) params.set("q", q);
3119
+ if (all) params.set("all", "true");
3120
+ else if (agentId) params.set("agentId", agentId);
3121
+ params.set("limit", String(limit));
3122
+ return `${ARCHIVE_SEARCH_PATH}?${params.toString()}`;
3123
+ }
3124
+ function toArchivedConversationOutput(item, timeZone) {
3125
+ return {
3126
+ conversation_id: item.id,
3127
+ title: item.title,
3128
+ last_preview: item.lastPreview,
3129
+ archived_at: item.archivedAt,
3130
+ archived_at_local: formatTimestampInTimeZone(item.archivedAt, timeZone),
3131
+ updated_at: item.updatedAt,
3132
+ updated_at_local: formatTimestampInTimeZone(item.updatedAt, timeZone),
3133
+ time_zone: timeZone,
3134
+ agent: item.agent ? {
3135
+ agent_id: item.agent.id,
3136
+ name: item.agent.name,
3137
+ avatar_url: item.agent.avatarUrl,
3138
+ scope: item.agent.scope
3139
+ } : null
3140
+ };
3141
+ }
3142
+ var findArchivedConversations = {
3143
+ service: "agent",
3144
+ command: "+find-archived-conversations",
3145
+ description: "Find archived conversations for one Agent or all Agents",
3146
+ flags: [
3147
+ {
3148
+ name: "q",
3149
+ type: "string",
3150
+ required: false,
3151
+ desc: "Optional keyword matched against conversation titles and message previews"
3152
+ },
3153
+ {
3154
+ name: "agent-id",
3155
+ type: "string",
3156
+ required: false,
3157
+ desc: "Agent ID; defaults to TE_AGENT_CURRENT_AGENT_ID inside an Agent sandbox"
3158
+ },
3159
+ {
3160
+ name: "all",
3161
+ type: "boolean",
3162
+ required: false,
3163
+ desc: "Set true to search archived conversations across all Agents"
3164
+ },
3165
+ {
3166
+ name: "limit",
3167
+ type: "number",
3168
+ required: false,
3169
+ default: DEFAULT_LIMIT,
3170
+ min: 1,
3171
+ max: 100,
3172
+ desc: "Maximum number of archived conversations to return, 1-100; default 20"
3173
+ },
3174
+ {
3175
+ name: "time-zone",
3176
+ type: "string",
3177
+ required: false,
3178
+ default: DEFAULT_TIME_ZONE,
3179
+ desc: "IANA time zone used for local timestamp fields; default Asia/Shanghai"
3180
+ }
3181
+ ],
3182
+ risk: "read",
3183
+ validate: validateFind,
3184
+ dryRun: (ctx) => ({
3185
+ method: "GET",
3186
+ url: buildArchivedConversationSearchPath(ctx)
3187
+ }),
3188
+ execute: async (ctx) => {
3189
+ const timeZone = readTimeZone(ctx);
3190
+ const result = await getAgentApi(
3191
+ ctx,
3192
+ buildArchivedConversationSearchPath(ctx)
3193
+ );
3194
+ return {
3195
+ items: result.items.map(
3196
+ (item) => toArchivedConversationOutput(item, timeZone)
3197
+ ),
3198
+ has_more: result.hasMore
3199
+ };
3200
+ }
3201
+ };
3202
+ var restoreConversation = {
3203
+ service: "agent",
3204
+ command: "+restore-conversation",
3205
+ description: "Restore an archived conversation by conversation ID",
3206
+ flags: [
3207
+ {
3208
+ name: "conversation-id",
3209
+ type: "string",
3210
+ required: true,
3211
+ desc: "Conversation ID returned by +find-archived-conversations"
3212
+ }
3213
+ ],
3214
+ risk: "write",
3215
+ dryRun: (ctx) => ({
3216
+ method: "POST",
3217
+ url: `${CONVERSATION_PATH}/${encodeURIComponent(ctx.str("conversationId"))}/restore`,
3218
+ body: {}
3219
+ }),
3220
+ execute: async (ctx) => {
3221
+ const result = await postAgentApi(
3222
+ ctx,
3223
+ `${CONVERSATION_PATH}/${encodeURIComponent(ctx.str("conversationId"))}/restore`,
3224
+ {}
3225
+ );
3226
+ return { changed: result.changed, conversation_id: result.conversationId };
3227
+ }
3228
+ };
3229
+
3230
+ // src/commands/te-agent/approval-cli-client.ts
3231
+ var APPROVAL_GATEWAY_DOMAIN = "approval";
3232
+ var DEFAULT_TE_CLAUDE_BASE_PATH = "/agent";
3233
+ function normalizeBasePath(value) {
3234
+ const trimmed = value.trim();
3235
+ if (!trimmed || trimmed === "/") return "";
3236
+ return `/${trimmed.replace(/^\/+|\/+$/g, "")}`;
3237
+ }
3238
+ function resolveApprovalApiBaseUrl(host) {
3239
+ const base = host.replace(/\/+$/, "");
3240
+ const basePath = normalizeBasePath(
3241
+ process.env.TE_CLAUDE_BASE_PATH ?? process.env.AE_API_PREFIX ?? DEFAULT_TE_CLAUDE_BASE_PATH
3242
+ );
3243
+ return basePath && !base.endsWith(basePath) ? `${base}${basePath}` : base;
3244
+ }
3245
+ function buildApprovalCliUrl(ctx, path) {
3246
+ return buildCapabilityGatewayUrl(resolveApprovalApiBaseUrl(ctx.host()), APPROVAL_GATEWAY_DOMAIN, path);
3247
+ }
3248
+ function requestApprovalCli(ctx, method, path, body, options = {}) {
3249
+ return callCapabilityApi(
3250
+ ctx.host(),
3251
+ APPROVAL_GATEWAY_DOMAIN,
3252
+ path,
3253
+ method,
3254
+ body,
3255
+ {
3256
+ apiBaseUrl: resolveApprovalApiBaseUrl(ctx.host()),
3257
+ ...options,
3258
+ retryOnInvalidTokenForbidden: false
3259
+ }
3260
+ );
3261
+ }
3262
+ function getApprovalCli(ctx, path) {
3263
+ return requestApprovalCli(ctx, "GET", path);
3264
+ }
3265
+ function postApprovalCli(ctx, path, body, options = {}) {
3266
+ return requestApprovalCli(ctx, "POST", path, body, options);
3267
+ }
3268
+
3269
+ // src/commands/te-agent/approval-commands.ts
3270
+ var SERVICE = "agent";
3271
+ var MAX_ID_LENGTH = 191;
3272
+ var MAX_VERSION = 2147483647;
3273
+ var DECISION_STATUSES = ["pending", "approved", "rejected", "cancelled"];
3274
+ var TASK_STATUSES = ["pending", "completed", "cancelled"];
3275
+ var EFFECT_STATUSES = ["pending", "running", "succeeded", "failed", "manual_required"];
3276
+ var LOCAL_DRY_RUN_HELP = [
3277
+ "Dry-run is a local request preview only.",
3278
+ "It does not verify server permissions, current approval state, or future conditional routing."
3279
+ ].join(" ");
3280
+ function validation(message, hint) {
3281
+ throw new CliValidationError(message, { hint });
3282
+ }
3283
+ function optionalString(ctx, name) {
3284
+ const value = ctx.str(name);
3285
+ return value ? value : void 0;
3286
+ }
3287
+ function validateStableId(ctx, name, flagName) {
3288
+ const value = ctx.str(name);
3289
+ if (!value || value !== value.trim() || value.length > MAX_ID_LENGTH) {
3290
+ validation(`--${flagName} must be a non-empty identifier of at most ${MAX_ID_LENGTH} characters`);
3291
+ }
3292
+ }
3293
+ function validateApprovalTypeId(ctx) {
3294
+ const value = ctx.str("approvalTypeId");
3295
+ if (!value || value.length > MAX_ID_LENGTH || !/^[a-z][a-z0-9_.-]*@[1-9]\d*$/.test(value)) {
3296
+ validation("--approval-type-id must use the format type.key@version");
3297
+ }
3298
+ const version = value.slice(value.lastIndexOf("@") + 1);
3299
+ if (BigInt(version) > BigInt(MAX_VERSION)) {
3300
+ validation("--approval-type-id version is out of range");
3301
+ }
3302
+ }
3303
+ function validateClientRequestId(ctx) {
3304
+ validateStableId(ctx, "clientRequestId", "client-request-id");
3305
+ if (ctx.str("clientRequestId").startsWith("system:")) {
3306
+ validation("--client-request-id must not use the reserved system: prefix");
3307
+ }
3308
+ }
3309
+ function validateText(ctx, name, flagName, options) {
3310
+ const value = ctx.str(name);
3311
+ if (!value && !options.required) return;
3312
+ if (!value || value.trim().length === 0) {
3313
+ validation(`--${flagName} must not be empty`);
3314
+ }
3315
+ if (value.length > options.maxLength) {
3316
+ validation(`--${flagName} must not exceed ${options.maxLength} characters`);
3317
+ }
3318
+ }
3319
+ function validateNonNegativeInteger(ctx, name, flagName) {
3320
+ const value = ctx.optionalNum(name);
3321
+ if (value === void 0 || !Number.isInteger(value) || value < 0 || value > MAX_VERSION) {
3322
+ validation(`--${flagName} must be an integer between 0 and ${MAX_VERSION}`);
3323
+ }
3324
+ }
3325
+ function validateExpectedVersion(ctx) {
3326
+ validateNonNegativeInteger(ctx, "expectedVersion", "expected-version");
3327
+ }
3328
+ function validateExpectedAttempt(ctx) {
3329
+ validateNonNegativeInteger(ctx, "expectedAttempt", "expected-attempt");
3330
+ }
3331
+ function assertAllowed(value, flagName, allowed) {
3332
+ if (value && !allowed.includes(value)) {
3333
+ validation(`--${flagName} must be one of: ${allowed.join(", ")}`);
3334
+ }
3335
+ }
3336
+ function validateDateRange(ctx) {
3337
+ const createdAfter = optionalString(ctx, "createdAfter");
3338
+ const createdBefore = optionalString(ctx, "createdBefore");
3339
+ if (createdAfter && Number.isNaN(Date.parse(createdAfter))) {
3340
+ validation("--created-after must be a valid ISO datetime");
3341
+ }
3342
+ if (createdBefore && Number.isNaN(Date.parse(createdBefore))) {
3343
+ validation("--created-before must be a valid ISO datetime");
3344
+ }
3345
+ if (createdAfter && createdBefore && Date.parse(createdAfter) >= Date.parse(createdBefore)) {
3346
+ validation("--created-after must be earlier than --created-before");
3347
+ }
3348
+ }
3349
+ function validateLimit(ctx) {
3350
+ const limit = ctx.optionalNum("limit") ?? 20;
3351
+ if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
3352
+ validation("--limit must be an integer between 1 and 100");
3353
+ }
3354
+ }
3355
+ function isRecord(value) {
3356
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3357
+ }
3358
+ function validateSnakeCaseValue(value, path = "payload") {
3359
+ if (Array.isArray(value)) {
3360
+ value.forEach((item, index) => validateSnakeCaseValue(item, `${path}[${index}]`));
3361
+ return;
3362
+ }
3363
+ if (!isRecord(value)) return;
3364
+ for (const [key, child] of Object.entries(value)) {
3365
+ if (!/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/.test(key)) {
3366
+ validation(`--payload keys must use snake_case (invalid key at ${path})`);
3367
+ }
3368
+ validateSnakeCaseValue(child, `${path}.${key}`);
3369
+ }
3370
+ }
3371
+ function approvalPayload(ctx) {
3372
+ const payload = ctx.json("payload");
3373
+ if (!isRecord(payload)) {
3374
+ validation("--payload must be a JSON object");
3375
+ }
3376
+ validateSnakeCaseValue(payload);
3377
+ return payload;
3378
+ }
3379
+ function buildQuery2(params) {
3380
+ const searchParams = new URLSearchParams();
3381
+ for (const [key, value] of Object.entries(params)) {
3382
+ if (value !== void 0 && value !== "") searchParams.set(key, String(value));
3383
+ }
3384
+ const query = searchParams.toString();
3385
+ return query ? `?${query}` : "";
3386
+ }
3387
+ function requestListPath(ctx) {
3388
+ return `requests${buildQuery2({
3389
+ cursor: optionalString(ctx, "cursor"),
3390
+ limit: ctx.optionalNum("limit") ?? 20,
3391
+ type_id: optionalString(ctx, "approvalTypeId"),
3392
+ status: optionalString(ctx, "status"),
3393
+ requester_id: optionalString(ctx, "requesterId"),
3394
+ created_after: optionalString(ctx, "createdAfter"),
3395
+ created_before: optionalString(ctx, "createdBefore")
3396
+ })}`;
3397
+ }
3398
+ function taskListPath(ctx) {
3399
+ return `tasks${buildQuery2({
3400
+ cursor: optionalString(ctx, "cursor"),
3401
+ limit: ctx.optionalNum("limit") ?? 20,
3402
+ status: optionalString(ctx, "status"),
3403
+ request_id: optionalString(ctx, "approvalRequestId"),
3404
+ created_after: optionalString(ctx, "createdAfter"),
3405
+ created_before: optionalString(ctx, "createdBefore")
3406
+ })}`;
3407
+ }
3408
+ function effectListPath(ctx) {
3409
+ return `effects${buildQuery2({
3410
+ cursor: optionalString(ctx, "cursor"),
3411
+ limit: ctx.optionalNum("limit") ?? 20,
3412
+ status: optionalString(ctx, "status"),
3413
+ request_id: optionalString(ctx, "approvalRequestId"),
3414
+ created_after: optionalString(ctx, "createdAfter"),
3415
+ created_before: optionalString(ctx, "createdBefore")
3416
+ })}`;
3417
+ }
3418
+ function submitBody(ctx) {
3419
+ return {
3420
+ type_id: ctx.str("approvalTypeId"),
3421
+ resource_id: ctx.str("resourceId"),
3422
+ reason: ctx.str("reason"),
3423
+ payload: approvalPayload(ctx),
3424
+ client_request_id: ctx.str("clientRequestId")
3425
+ };
3426
+ }
3427
+ function cancelBody(ctx) {
3428
+ return {
3429
+ expected_version: ctx.num("expectedVersion"),
3430
+ ...optionalString(ctx, "reason") ? { reason: ctx.str("reason") } : {},
3431
+ client_request_id: ctx.str("clientRequestId")
3432
+ };
3433
+ }
3434
+ function approveBody(ctx) {
3435
+ return {
3436
+ expected_version: ctx.num("expectedVersion"),
3437
+ ...optionalString(ctx, "note") ? { note: ctx.str("note") } : {},
3438
+ client_request_id: ctx.str("clientRequestId")
3439
+ };
3440
+ }
3441
+ function rejectBody(ctx) {
3442
+ return {
3443
+ expected_version: ctx.num("expectedVersion"),
3444
+ reason: ctx.str("reason"),
3445
+ client_request_id: ctx.str("clientRequestId")
3446
+ };
3447
+ }
3448
+ function retryEffectBody(ctx) {
3449
+ return {
3450
+ expected_version: ctx.num("expectedVersion"),
3451
+ expected_attempt: ctx.num("expectedAttempt"),
3452
+ reason: ctx.str("reason"),
3453
+ confirm_risk: true,
3454
+ client_request_id: ctx.str("clientRequestId")
3455
+ };
3456
+ }
3457
+ var approvalTypeIdFlag = {
3458
+ name: "approval-type-id",
3459
+ type: "string",
3460
+ required: true,
3461
+ maxLength: MAX_ID_LENGTH,
3462
+ desc: "Versioned approval type ID, for example skill.publish@1"
3463
+ };
3464
+ var approvalRequestIdFlag = {
3465
+ name: "approval-request-id",
3466
+ type: "string",
3467
+ required: true,
3468
+ maxLength: MAX_ID_LENGTH,
3469
+ desc: "Approval request ID"
3470
+ };
3471
+ var taskIdFlag = {
3472
+ name: "task-id",
3473
+ type: "string",
3474
+ required: true,
3475
+ maxLength: MAX_ID_LENGTH,
3476
+ desc: "Approval task ID"
3477
+ };
3478
+ var effectIdFlag = {
3479
+ name: "effect-id",
3480
+ type: "string",
3481
+ required: true,
3482
+ maxLength: MAX_ID_LENGTH,
3483
+ desc: "Approval Effect ID"
3484
+ };
3485
+ var clientRequestIdFlag = {
3486
+ name: "client-request-id",
3487
+ type: "string",
3488
+ required: true,
3489
+ maxLength: MAX_ID_LENGTH,
3490
+ desc: "Caller-generated idempotency key"
3491
+ };
3492
+ var expectedVersionFlag = {
3493
+ name: "expected-version",
3494
+ type: "number",
3495
+ required: true,
3496
+ min: 0,
3497
+ max: MAX_VERSION,
3498
+ desc: "Expected optimistic version from the latest request, task, or Effect read"
3499
+ };
3500
+ var expectedAttemptFlag = {
3501
+ name: "expected-attempt",
3502
+ type: "number",
3503
+ required: true,
3504
+ min: 0,
3505
+ max: MAX_VERSION,
3506
+ desc: "Expected Effect attempt from the latest Effect read"
3507
+ };
3508
+ var pageFlags = [
3509
+ { name: "cursor", type: "string", required: false, maxLength: 1024, desc: "Opaque cursor from the previous page" },
3510
+ { name: "limit", type: "number", required: false, default: 20, min: 1, max: 100, desc: "Page size from 1 to 100" },
3511
+ { name: "created-after", type: "string", required: false, desc: "Include records created at or after this ISO datetime" },
3512
+ { name: "created-before", type: "string", required: false, desc: "Include records created before this ISO datetime" }
3513
+ ];
3514
+ var listApprovalTypes = {
3515
+ service: SERVICE,
3516
+ resource: "approval-type",
3517
+ command: "list",
3518
+ description: "List registered versioned approval types and their input contracts",
3519
+ flags: [],
3520
+ risk: "read",
3521
+ dryRun: (ctx) => ({ method: "GET", url: buildApprovalCliUrl(ctx, "types") }),
3522
+ execute: (ctx) => getApprovalCli(ctx, "types")
3523
+ };
3524
+ var getApprovalType = {
3525
+ service: SERVICE,
3526
+ resource: "approval-type",
3527
+ command: "get",
3528
+ description: "Get one versioned approval type and its input contract",
3529
+ flags: [approvalTypeIdFlag],
3530
+ risk: "read",
3531
+ validate: validateApprovalTypeId,
3532
+ dryRun: (ctx) => ({
3533
+ method: "GET",
3534
+ url: buildApprovalCliUrl(ctx, `types/${encodeURIComponent(ctx.str("approvalTypeId"))}`)
3535
+ }),
3536
+ execute: (ctx) => getApprovalCli(ctx, `types/${encodeURIComponent(ctx.str("approvalTypeId"))}`)
3537
+ };
3538
+ var listApprovalRequests = {
3539
+ service: SERVICE,
3540
+ resource: "approval-request",
3541
+ command: "list",
3542
+ description: "List approval requests visible to the current user",
3543
+ flags: [
3544
+ ...pageFlags,
3545
+ { name: "approval-type-id", type: "string", required: false, maxLength: MAX_ID_LENGTH, desc: "Filter by versioned approval type ID" },
3546
+ { name: "status", type: "string", required: false, desc: `Filter by decision status: ${DECISION_STATUSES.join(" | ")}` },
3547
+ { name: "requester-id", type: "string", required: false, maxLength: MAX_ID_LENGTH, desc: "Filter by requester user ID when authorized" }
3548
+ ],
3549
+ risk: "read",
3550
+ validate: (ctx) => {
3551
+ validateLimit(ctx);
3552
+ validateDateRange(ctx);
3553
+ assertAllowed(optionalString(ctx, "status"), "status", DECISION_STATUSES);
3554
+ if (optionalString(ctx, "approvalTypeId")) validateApprovalTypeId(ctx);
3555
+ if (optionalString(ctx, "requesterId")) validateStableId(ctx, "requesterId", "requester-id");
3556
+ },
3557
+ dryRun: (ctx) => ({ method: "GET", url: buildApprovalCliUrl(ctx, requestListPath(ctx)) }),
3558
+ execute: (ctx) => getApprovalCli(ctx, requestListPath(ctx))
3559
+ };
3560
+ var getApprovalRequest = {
3561
+ service: SERVICE,
3562
+ resource: "approval-request",
3563
+ command: "get",
3564
+ description: "Get one approval request by approval request ID",
3565
+ flags: [approvalRequestIdFlag],
3566
+ risk: "read",
3567
+ validate: (ctx) => validateStableId(ctx, "approvalRequestId", "approval-request-id"),
3568
+ dryRun: (ctx) => ({
3569
+ method: "GET",
3570
+ url: buildApprovalCliUrl(ctx, `requests/${encodeURIComponent(ctx.str("approvalRequestId"))}`)
3571
+ }),
3572
+ execute: (ctx) => getApprovalCli(ctx, `requests/${encodeURIComponent(ctx.str("approvalRequestId"))}`)
3573
+ };
3574
+ var submitApprovalRequest = {
3575
+ service: SERVICE,
3576
+ resource: "approval-request",
3577
+ command: "submit",
3578
+ description: "Submit a resource snapshot to a versioned approval type",
3579
+ helpText: LOCAL_DRY_RUN_HELP,
3580
+ flags: [
3581
+ approvalTypeIdFlag,
3582
+ { name: "resource-id", type: "string", required: true, maxLength: MAX_ID_LENGTH, desc: "Business resource ID resolved by the selected approval type" },
3583
+ { name: "reason", type: "string", required: true, maxLength: 2e3, desc: "Submission reason" },
3584
+ { name: "payload", type: "json", required: true, desc: "Type-specific snake_case JSON object from approval-type get" },
3585
+ clientRequestIdFlag
3586
+ ],
3587
+ risk: "write",
3588
+ validate: (ctx) => {
3589
+ validateApprovalTypeId(ctx);
3590
+ validateStableId(ctx, "resourceId", "resource-id");
3591
+ validateText(ctx, "reason", "reason", { required: true, maxLength: 2e3 });
3592
+ validateClientRequestId(ctx);
3593
+ approvalPayload(ctx);
3594
+ },
3595
+ dryRun: (ctx) => ({ method: "POST", url: buildApprovalCliUrl(ctx, "requests"), body: submitBody(ctx) }),
3596
+ execute: (ctx) => postApprovalCli(ctx, "requests", submitBody(ctx))
3597
+ };
3598
+ var cancelApprovalRequest = {
3599
+ service: SERVICE,
3600
+ resource: "approval-request",
3601
+ command: "cancel",
3602
+ description: "Cancel a pending approval request with optimistic concurrency control",
3603
+ helpText: LOCAL_DRY_RUN_HELP,
3604
+ flags: [
3605
+ approvalRequestIdFlag,
3606
+ expectedVersionFlag,
3607
+ { name: "reason", type: "string", required: false, maxLength: 2e3, desc: "Optional cancellation reason; required when cancelling another user request" },
3608
+ clientRequestIdFlag
3609
+ ],
3610
+ risk: "write",
3611
+ validate: (ctx) => {
3612
+ validateStableId(ctx, "approvalRequestId", "approval-request-id");
3613
+ validateExpectedVersion(ctx);
3614
+ validateText(ctx, "reason", "reason", { required: false, maxLength: 2e3 });
3615
+ validateClientRequestId(ctx);
3616
+ },
3617
+ dryRun: (ctx) => ({
3618
+ method: "POST",
3619
+ url: buildApprovalCliUrl(ctx, `requests/${encodeURIComponent(ctx.str("approvalRequestId"))}/cancel`),
3620
+ body: cancelBody(ctx)
3621
+ }),
3622
+ execute: (ctx) => postApprovalCli(
3623
+ ctx,
3624
+ `requests/${encodeURIComponent(ctx.str("approvalRequestId"))}/cancel`,
3625
+ cancelBody(ctx)
3626
+ )
3627
+ };
3628
+ var listApprovalTasks = {
3629
+ service: SERVICE,
3630
+ resource: "approval-task",
3631
+ command: "list",
3632
+ description: "List approval tasks currently visible to the current approver",
3633
+ flags: [
3634
+ ...pageFlags,
3635
+ { name: "status", type: "string", required: false, desc: `Filter by task status: ${TASK_STATUSES.join(" | ")}` },
3636
+ { name: "approval-request-id", type: "string", required: false, maxLength: MAX_ID_LENGTH, desc: "Filter by approval request ID" }
3637
+ ],
3638
+ risk: "read",
3639
+ validate: (ctx) => {
3640
+ validateLimit(ctx);
3641
+ validateDateRange(ctx);
3642
+ assertAllowed(optionalString(ctx, "status"), "status", TASK_STATUSES);
3643
+ if (optionalString(ctx, "approvalRequestId")) {
3644
+ validateStableId(ctx, "approvalRequestId", "approval-request-id");
3645
+ }
3646
+ },
3647
+ dryRun: (ctx) => ({ method: "GET", url: buildApprovalCliUrl(ctx, taskListPath(ctx)) }),
3648
+ execute: (ctx) => getApprovalCli(ctx, taskListPath(ctx))
3649
+ };
3650
+ var getApprovalTask = {
3651
+ service: SERVICE,
3652
+ resource: "approval-task",
3653
+ command: "get",
3654
+ description: "Get one approval task by task ID",
3655
+ flags: [taskIdFlag],
3656
+ risk: "read",
3657
+ validate: (ctx) => validateStableId(ctx, "taskId", "task-id"),
3658
+ dryRun: (ctx) => ({
3659
+ method: "GET",
3660
+ url: buildApprovalCliUrl(ctx, `tasks/${encodeURIComponent(ctx.str("taskId"))}`)
3661
+ }),
3662
+ execute: (ctx) => getApprovalCli(ctx, `tasks/${encodeURIComponent(ctx.str("taskId"))}`)
3663
+ };
3664
+ var approveApprovalTask = {
3665
+ service: SERVICE,
3666
+ resource: "approval-task",
3667
+ command: "approve",
3668
+ description: "Approve a pending approval task with optimistic concurrency control",
3669
+ helpText: LOCAL_DRY_RUN_HELP,
3670
+ flags: [
3671
+ taskIdFlag,
3672
+ expectedVersionFlag,
3673
+ { name: "note", type: "string", required: false, maxLength: 2e3, desc: "Optional approval note" },
3674
+ clientRequestIdFlag
3675
+ ],
3676
+ risk: "write",
3677
+ validate: (ctx) => {
3678
+ validateStableId(ctx, "taskId", "task-id");
3679
+ validateExpectedVersion(ctx);
3680
+ validateText(ctx, "note", "note", { required: false, maxLength: 2e3 });
3681
+ validateClientRequestId(ctx);
3682
+ },
3683
+ dryRun: (ctx) => ({
3684
+ method: "POST",
3685
+ url: buildApprovalCliUrl(ctx, `tasks/${encodeURIComponent(ctx.str("taskId"))}/approve`),
3686
+ body: approveBody(ctx)
3687
+ }),
3688
+ execute: (ctx) => postApprovalCli(
3689
+ ctx,
3690
+ `tasks/${encodeURIComponent(ctx.str("taskId"))}/approve`,
3691
+ approveBody(ctx)
3692
+ )
3693
+ };
3694
+ var rejectApprovalTask = {
3695
+ service: SERVICE,
3696
+ resource: "approval-task",
3697
+ command: "reject",
3698
+ description: "Reject a pending approval task with a required reason",
3699
+ helpText: LOCAL_DRY_RUN_HELP,
3700
+ flags: [
3701
+ taskIdFlag,
3702
+ expectedVersionFlag,
3703
+ { name: "reason", type: "string", required: true, maxLength: 2e3, desc: "Rejection reason" },
3704
+ clientRequestIdFlag
3705
+ ],
3706
+ risk: "write",
3707
+ validate: (ctx) => {
3708
+ validateStableId(ctx, "taskId", "task-id");
3709
+ validateExpectedVersion(ctx);
3710
+ validateText(ctx, "reason", "reason", { required: true, maxLength: 2e3 });
3711
+ validateClientRequestId(ctx);
3712
+ },
3713
+ dryRun: (ctx) => ({
3714
+ method: "POST",
3715
+ url: buildApprovalCliUrl(ctx, `tasks/${encodeURIComponent(ctx.str("taskId"))}/reject`),
3716
+ body: rejectBody(ctx)
3717
+ }),
3718
+ execute: (ctx) => postApprovalCli(
3719
+ ctx,
3720
+ `tasks/${encodeURIComponent(ctx.str("taskId"))}/reject`,
3721
+ rejectBody(ctx)
3722
+ )
3723
+ };
3724
+ var listApprovalEffects = {
3725
+ service: SERVICE,
3726
+ resource: "approval-effect",
3727
+ command: "list",
3728
+ description: "List approval Effects visible to the current company administrator",
3729
+ flags: [
3730
+ ...pageFlags,
3731
+ { name: "status", type: "string", required: false, desc: `Filter by Effect status: ${EFFECT_STATUSES.join(" | ")}` },
3732
+ { name: "approval-request-id", type: "string", required: false, maxLength: MAX_ID_LENGTH, desc: "Filter by approval request ID" }
3733
+ ],
3734
+ risk: "read",
3735
+ validate: (ctx) => {
3736
+ validateLimit(ctx);
3737
+ validateDateRange(ctx);
3738
+ assertAllowed(optionalString(ctx, "status"), "status", EFFECT_STATUSES);
3739
+ if (optionalString(ctx, "approvalRequestId")) {
3740
+ validateStableId(ctx, "approvalRequestId", "approval-request-id");
3741
+ }
3742
+ },
3743
+ dryRun: (ctx) => ({ method: "GET", url: buildApprovalCliUrl(ctx, effectListPath(ctx)) }),
3744
+ execute: (ctx) => getApprovalCli(ctx, effectListPath(ctx))
3745
+ };
3746
+ var getApprovalEffect = {
3747
+ service: SERVICE,
3748
+ resource: "approval-effect",
3749
+ command: "get",
3750
+ description: "Get one approval Effect by Effect ID",
3751
+ flags: [effectIdFlag],
3752
+ risk: "read",
3753
+ validate: (ctx) => validateStableId(ctx, "effectId", "effect-id"),
3754
+ dryRun: (ctx) => ({
3755
+ method: "GET",
3756
+ url: buildApprovalCliUrl(ctx, `effects/${encodeURIComponent(ctx.str("effectId"))}`)
3757
+ }),
3758
+ execute: (ctx) => getApprovalCli(ctx, `effects/${encodeURIComponent(ctx.str("effectId"))}`)
3759
+ };
3760
+ var retryApprovalEffect = {
3761
+ service: SERVICE,
3762
+ resource: "approval-effect",
3763
+ command: "retry",
3764
+ description: "Manually retry a failed or manual-required approval Effect",
3765
+ helpText: `${LOCAL_DRY_RUN_HELP} Actual execution requires confirmation; pass global --yes only after explicit user authorization.`,
3766
+ flags: [
3767
+ effectIdFlag,
3768
+ expectedVersionFlag,
3769
+ expectedAttemptFlag,
3770
+ { name: "reason", type: "string", required: true, maxLength: 2e3, desc: "Auditable manual retry reason" },
3771
+ clientRequestIdFlag
3772
+ ],
3773
+ risk: "high-risk-write",
3774
+ validate: (ctx) => {
3775
+ validateStableId(ctx, "effectId", "effect-id");
3776
+ validateExpectedVersion(ctx);
3777
+ validateExpectedAttempt(ctx);
3778
+ validateText(ctx, "reason", "reason", { required: true, maxLength: 2e3 });
3779
+ validateClientRequestId(ctx);
3780
+ },
3781
+ dryRun: (ctx) => ({
3782
+ method: "POST",
3783
+ url: buildApprovalCliUrl(ctx, `effects/${encodeURIComponent(ctx.str("effectId"))}/retry`),
3784
+ body: retryEffectBody(ctx)
3785
+ }),
3786
+ execute: (ctx) => postApprovalCli(
3787
+ ctx,
3788
+ `effects/${encodeURIComponent(ctx.str("effectId"))}/retry`,
3789
+ retryEffectBody(ctx)
3790
+ )
3791
+ };
3792
+
3793
+ // src/commands/te-agent/index.ts
3794
+ var commands = [
3795
+ // Agent CRUD
3796
+ listAgents,
3797
+ createAgent,
3798
+ updateAgent,
3799
+ delAgent,
3800
+ getAgent,
3801
+ // Model management + test
3802
+ listModels,
3803
+ addModel,
3804
+ delModel,
3805
+ toggleModel,
3806
+ updateModel,
3807
+ testModel,
3808
+ // MCP server management + market + OAuth + credentials
3809
+ listMcps,
3810
+ addMcp,
3811
+ delMcp,
3812
+ toggleMcp,
3813
+ listMcpMarket,
3814
+ setMcpMeta,
3815
+ updateMcp,
3816
+ mcpTools,
3817
+ mcpAuthStart,
3818
+ mcpAuthStatus,
3819
+ mcpAuthDisconnect,
3820
+ listMcpCredentials,
3821
+ setMcpCredential,
3822
+ autoProvisionMcpCredentials,
3823
+ mcpToken,
3824
+ mcpStats,
3825
+ // Skill management + market + copy
3826
+ listSkills,
3827
+ addSkill,
3828
+ delSkill,
3829
+ toggleSkill,
3830
+ listSkillMarket,
3831
+ setSkillMeta,
3832
+ copySkill,
3833
+ // Skill content + assets (references / assets / scripts)
3834
+ editSkill,
3835
+ getSkillContent,
3836
+ listSkillAssets,
3837
+ uploadSkillAsset,
3838
+ readSkillAsset,
3839
+ delSkillAsset,
3840
+ listSkillReferences,
3841
+ uploadSkillReference,
3842
+ readSkillReference,
3843
+ delSkillReference,
3844
+ listSkillScripts,
3845
+ uploadSkillScript,
3846
+ readSkillScript,
3847
+ delSkillScript,
3848
+ uploadSkill,
3849
+ rescanSkills,
3850
+ // Skill approval (company-scope publish)
3851
+ submitSkill,
3852
+ listSkillSubmissions,
3853
+ cancelSkillSubmission,
3854
+ approveSkill,
3855
+ rejectSkill,
3856
+ // Generic versioned approval workflow
3857
+ listApprovalTypes,
3858
+ getApprovalType,
3859
+ listApprovalRequests,
3860
+ getApprovalRequest,
3861
+ submitApprovalRequest,
3862
+ cancelApprovalRequest,
3863
+ listApprovalTasks,
3864
+ getApprovalTask,
3865
+ approveApprovalTask,
3866
+ rejectApprovalTask,
3867
+ listApprovalEffects,
3868
+ getApprovalEffect,
3869
+ retryApprovalEffect,
3870
+ // Skill share (peer-to-peer)
3871
+ shareSkill,
3872
+ listSkillShares,
3873
+ acceptSkillShare,
3874
+ rejectSkillShare,
3875
+ // Attachment library management
3876
+ listAttachments,
3877
+ addAttachment,
3878
+ delAttachment,
3879
+ attachmentStats,
3880
+ // Automate tasks
3881
+ listAutomations,
3882
+ createAutomation,
3883
+ updateAutomation,
3884
+ // Archived conversations
3885
+ findArchivedConversations,
3886
+ restoreConversation,
3887
+ // Sandbox tools (local scan of /home/ta/.local/bin managed shims)
3888
+ listSandboxTools
3889
+ ];
3890
+ var te_agent_default = commands;
3891
+ export {
3892
+ te_agent_default as default
3893
+ };