@thinkingai/ae-cli 6.1.27 → 6.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -3
- package/README.zh.md +29 -3
- package/dist/{auth-WA7YGGRT.js → auth-NKD5Z5BQ.js} +150 -38
- package/dist/{automation-VAAQBM7Y.js → automation-K32V2NKP.js} +94 -38
- package/dist/{capability-GAAYJ3IQ.js → capability-4CGSL7PK.js} +9 -8
- package/dist/{chunk-CT7QDJS6.js → chunk-2IYIYSUO.js} +2 -2
- package/dist/{chunk-3YVEAZUN.js → chunk-2UWS5CUP.js} +32 -21
- package/dist/{chunk-6VNIR4AP.js → chunk-ELCR235M.js} +26 -19
- package/dist/{chunk-RPBOAQQQ.js → chunk-GI5BMEZO.js} +1 -1
- package/dist/{chunk-7KU2WNQE.js → chunk-GTPWDLTE.js} +7 -6
- package/dist/chunk-JJJIP2XQ.js +105 -0
- package/dist/{chunk-5XJYLEVC.js → chunk-KHS64JZQ.js} +4 -4
- package/dist/{chunk-ZL7SGNIA.js → chunk-LMCYSVVA.js} +11 -13
- package/dist/{chunk-OP44TT4H.js → chunk-P6VFCH3P.js} +4 -2
- package/dist/{chunk-GHXZK54S.js → chunk-P7KL7IOH.js} +41 -13
- package/dist/{chunk-AP7YP2NX.js → chunk-QSAR3GHY.js} +2 -2
- package/dist/{chunk-VZZNLV3I.js → chunk-QW3R6O7L.js} +14 -6
- package/dist/{chunk-S6M42KND.js → chunk-T44M3PLZ.js} +1 -1
- package/dist/{chunk-AQJPNWZF.js → chunk-UF244C5C.js} +3 -3
- package/dist/{chunk-MWIA43UJ.js → chunk-UJ7UPRXK.js} +3 -3
- package/dist/{chunk-Q5US7JC5.js → chunk-UUD5RB36.js} +3 -3
- package/dist/chunk-X7DRLE62.js +233 -0
- package/dist/{chunk-WNGFSIOB.js → chunk-ZW4VMY5H.js} +103 -6
- package/dist/{community-report-client-PEERQCX2.js → community-report-client-S2K3A3Q6.js} +1 -1
- package/dist/{config-JOD5DOPE.js → config-ASSAAIOI.js} +6 -5
- package/dist/{context-NGVFPCBK.js → context-6RWLVOM5.js} +4 -4
- package/dist/{data-integration-BCLQFTGU.js → data-integration-EXSUPUDZ.js} +6 -6
- package/dist/evaluation-5YT4QLCL.js +3714 -0
- package/dist/index.js +96 -52
- package/dist/{local-data-upload-client-TWMHFLUA.js → local-data-upload-client-7HCPGIS3.js} +1 -1
- package/dist/{memory-CQKH2JAV.js → memory-VCYLVPMI.js} +6 -6
- package/dist/{metadata-NR3PHR23.js → metadata-YGI5M6OF.js} +8 -8
- package/dist/{model-VX5M2CJ6.js → model-DPJHSD73.js} +4 -4
- package/dist/{personal-semantic-preference-2RAI36P3.js → personal-semantic-preference-76TBKAPY.js} +6 -6
- package/dist/{project-semantic-3BUGP3ZM.js → project-semantic-XOEBO2Q5.js} +6 -6
- package/dist/{sync-RZIAV37C.js → sync-7PP6KQ75.js} +7 -7
- package/dist/{te-agent-AORRE2FM.js → te-agent-PJVAPKBD.js} +753 -94
- package/dist/{te-analysis-GP7DSQ7Q.js → te-analysis-OX62G5VD.js} +411 -79
- package/dist/{te-community-42M7ICDO.js → te-community-QN3WMPNT.js} +6 -4
- package/dist/{te-dataops-BNKNZ4F2.js → te-dataops-UKD2XN3E.js} +8 -6
- package/dist/{te-engage-2CO6LRCX.js → te-engage-X3DIXPRA.js} +6 -6
- package/dist/{te-experiment-652CLXMU.js → te-experiment-MEIIK3DP.js} +6 -6
- package/dist/{te-kb-ULATOTQ3.js → te-kb-73EWDFDF.js} +7 -7
- package/dist/{te-system-UGHVKBVV.js → te-system-IE7NCKC3.js} +6 -6
- package/dist/{te-team-YA6SNOJ3.js → te-team-MGQ5CNRW.js} +63 -41
- package/dist/{things-DTCOQIQB.js → things-4JIBCA55.js} +7 -7
- package/dist/{update-ESNYKUVR.js → update-AX66IFMJ.js} +4 -4
- package/dist/{workspace-JEOHKFPX.js → workspace-Q5NMEKEN.js} +6 -6
- package/package.json +13 -8
- package/skills/ae-agent/SKILL.md +22 -3
- package/skills/ae-agent/references/command_index.md +8 -0
- package/skills/ae-agent/references/resource-package.md +53 -0
- package/skills/ae-analysis/SKILL.md +12 -3
- package/skills/ae-analysis/references/adhoc_export.md +1 -1
- package/skills/ae-analysis/references/agent_review_preflight.md +4 -0
- package/skills/ae-analysis/references/agent_review_submit_to_page.md +4 -0
- package/skills/ae-analysis/references/ai_models/event.md +58 -2
- package/skills/ae-analysis/references/ai_models/rank_list.md +1 -0
- package/skills/ae-analysis/references/ai_models/retention.md +2 -0
- package/skills/ae-analysis/references/ai_models/revenue.md +2 -0
- package/skills/ae-analysis/references/analysis_data_export.md +11 -1
- package/skills/ae-analysis/references/asset_batch_info_export.md +2 -2
- package/skills/ae-analysis/references/asset_batch_sql_export.md +2 -2
- package/skills/ae-analysis/references/asset_export.md +1 -1
- package/skills/ae-analysis/references/bi_panel_page_data_export.md +1 -1
- package/skills/ae-analysis/references/check_export.md +1 -1
- package/skills/ae-analysis/references/command_index.md +34 -25
- package/skills/ae-analysis/references/dashboard_report_data_export.md +2 -0
- package/skills/ae-analysis/references/dashboard_report_get.md +6 -2
- package/skills/ae-analysis/references/dashboard_report_update.md +24 -5
- package/skills/ae-analysis/references/feedback_submit.md +1 -1
- package/skills/ae-analysis/references/governance_recommendation_export.md +10 -2
- package/skills/ae-analysis/references/live_data_export.md +1 -1
- package/skills/ae-analysis/references/metric_create.md +29 -0
- package/skills/ae-analysis/references/metric_get.md +2 -0
- package/skills/ae-analysis/references/metric_update.md +2 -0
- package/skills/ae-analysis/references/operation_record_export.md +1 -1
- package/skills/ae-analysis/references/plan_change_log_export.md +1 -1
- package/skills/ae-analysis/references/plan_export.md +1 -1
- package/skills/ae-analysis/references/project_info_get.md +4 -0
- package/skills/ae-analysis/references/project_member_group_add_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_create.md +25 -0
- package/skills/ae-analysis/references/project_member_group_delete.md +34 -0
- package/skills/ae-analysis/references/project_member_group_list.md +29 -0
- package/skills/ae-analysis/references/project_member_group_members.md +28 -0
- package/skills/ae-analysis/references/project_member_group_remove_members.md +35 -0
- package/skills/ae-analysis/references/project_member_group_rename.md +26 -0
- package/skills/ae-analysis/references/project_semantic_knowledge_wiki_plan_schema.md +6 -1
- package/skills/ae-analysis/references/report_data_export.md +1 -1
- package/skills/ae-analysis/references/scenario_append.md +25 -0
- package/skills/ae-analysis/references/scenario_collect.md +35 -0
- package/skills/ae-analysis/references/scenario_evaluation.md +30 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/build-project-semantic-wiki.mjs +73 -4
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/default-compile-schema.md +5 -1
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/execution-contract.mjs +173 -0
- package/skills/ae-analysis/scripts/project-semantic-knowledge-wiki/generate-build-ir.mjs +109 -64
- package/skills/ae-automation/SKILL.md +2 -2
- package/skills/ae-automation/references/cli.md +18 -1
- package/skills/ae-capability/SKILL.md +7 -3
- package/skills/ae-evaluation/SKILL.md +83 -0
- package/skills/ae-evaluation/references/access-and-members.md +55 -0
- package/skills/ae-evaluation/references/connections.md +78 -0
- package/skills/ae-evaluation/references/datasets.md +57 -0
- package/skills/ae-evaluation/references/evaluators.md +81 -0
- package/skills/ae-evaluation/references/files.md +33 -0
- package/skills/ae-evaluation/references/integrations.md +39 -0
- package/skills/ae-evaluation/references/runs.md +160 -0
- package/skills/ae-evaluation/references/schedules.md +31 -0
- package/skills/ae-kb/SKILL.md +1 -2
- package/skills/ae-metadata/SKILL.md +2 -1
- package/skills/ae-metadata/references/metadata_data_table_download.md +7 -1
- package/skills/ae-metadata/references/metadata_data_table_get.md +2 -0
- package/skills/ae-system/SKILL.md +1 -1
- package/skills/ae-team/SKILL.md +2 -2
- package/skills/ae-team/references/run-start.md +1 -0
- package/skills/ae-team/references/run-watch.md +7 -5
- package/skills/ae-things/SKILL.md +53 -51
- package/skills/ae-things/references/cli.md +56 -54
- package/skills/ae-things-progress/SKILL.md +20 -20
- package/skills/ae-things-review/SKILL.md +19 -19
- package/skills/ae-workspace/SKILL.md +1 -1
- package/dist/chunk-CI24BDR2.js +0 -43
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
workspaceResourcePath,
|
|
12
12
|
workspaceTargetFlags,
|
|
13
13
|
workspaceTargetPath
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-UUD5RB36.js";
|
|
15
15
|
import {
|
|
16
16
|
currentAgentSpaceId
|
|
17
17
|
} from "./chunk-RK6GLDGI.js";
|
|
@@ -19,24 +19,31 @@ import {
|
|
|
19
19
|
deleteAgentApi,
|
|
20
20
|
getAgentApi,
|
|
21
21
|
getAgentBuffer,
|
|
22
|
+
isTransientResourcePackageError,
|
|
22
23
|
patchAgentApi,
|
|
23
24
|
postAgentApi,
|
|
24
25
|
putAgentApi,
|
|
26
|
+
requestResourcePackageApi,
|
|
27
|
+
requestResourcePackageRaw,
|
|
28
|
+
resourcePackagePreflightChange,
|
|
25
29
|
uploadAgentApi
|
|
26
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-JJJIP2XQ.js";
|
|
27
31
|
import {
|
|
32
|
+
TeAgentApiError,
|
|
28
33
|
resolveTeClaudeBaseUrl
|
|
29
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-2UWS5CUP.js";
|
|
30
35
|
import {
|
|
31
36
|
buildCapabilityGatewayUrl,
|
|
32
37
|
callCapabilityApi
|
|
33
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-QW3R6O7L.js";
|
|
34
39
|
import "./chunk-Y74WTIKJ.js";
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import
|
|
40
|
+
import "./chunk-P7KL7IOH.js";
|
|
41
|
+
import {
|
|
42
|
+
getConfigDir
|
|
43
|
+
} from "./chunk-LMCYSVVA.js";
|
|
37
44
|
import {
|
|
38
45
|
CliValidationError
|
|
39
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-ZW4VMY5H.js";
|
|
40
47
|
|
|
41
48
|
// src/commands/te-agent/notifications.ts
|
|
42
49
|
import { openSync, closeSync, fstatSync, readSync } from "fs";
|
|
@@ -44,14 +51,14 @@ import { openSync, closeSync, fstatSync, readSync } from "fs";
|
|
|
44
51
|
// src/commands/te-agent/approval-cli-client.ts
|
|
45
52
|
var APPROVAL_GATEWAY_DOMAIN = "approval";
|
|
46
53
|
var resolveApprovalApiBaseUrl = resolveTeClaudeBaseUrl;
|
|
47
|
-
function buildApprovalCliUrl(ctx,
|
|
48
|
-
return buildCapabilityGatewayUrl(resolveApprovalApiBaseUrl(ctx.host()), APPROVAL_GATEWAY_DOMAIN,
|
|
54
|
+
function buildApprovalCliUrl(ctx, path2) {
|
|
55
|
+
return buildCapabilityGatewayUrl(resolveApprovalApiBaseUrl(ctx.host()), APPROVAL_GATEWAY_DOMAIN, path2);
|
|
49
56
|
}
|
|
50
|
-
function requestApprovalCli(ctx, method,
|
|
57
|
+
function requestApprovalCli(ctx, method, path2, body, options = {}) {
|
|
51
58
|
return callCapabilityApi(
|
|
52
59
|
ctx.host(),
|
|
53
60
|
APPROVAL_GATEWAY_DOMAIN,
|
|
54
|
-
|
|
61
|
+
path2,
|
|
55
62
|
method,
|
|
56
63
|
body,
|
|
57
64
|
{
|
|
@@ -61,11 +68,11 @@ function requestApprovalCli(ctx, method, path, body, options = {}) {
|
|
|
61
68
|
}
|
|
62
69
|
);
|
|
63
70
|
}
|
|
64
|
-
function getApprovalCli(ctx,
|
|
65
|
-
return requestApprovalCli(ctx, "GET",
|
|
71
|
+
function getApprovalCli(ctx, path2) {
|
|
72
|
+
return requestApprovalCli(ctx, "GET", path2);
|
|
66
73
|
}
|
|
67
|
-
function postApprovalCli(ctx,
|
|
68
|
-
return requestApprovalCli(ctx, "POST",
|
|
74
|
+
function postApprovalCli(ctx, path2, body, options = {}) {
|
|
75
|
+
return requestApprovalCli(ctx, "POST", path2, body, options);
|
|
69
76
|
}
|
|
70
77
|
|
|
71
78
|
// src/commands/te-agent/notifications.ts
|
|
@@ -204,7 +211,7 @@ function query(ctx, mode) {
|
|
|
204
211
|
}
|
|
205
212
|
return params.toString() ? `?${params}` : "";
|
|
206
213
|
}
|
|
207
|
-
function command(name, description, flags, method,
|
|
214
|
+
function command(name, description, flags, method, path2, body) {
|
|
208
215
|
return {
|
|
209
216
|
service: "agent",
|
|
210
217
|
resource: "notification",
|
|
@@ -214,7 +221,7 @@ function command(name, description, flags, method, path, body) {
|
|
|
214
221
|
flags,
|
|
215
222
|
risk: method === "GET" ? "read" : "write",
|
|
216
223
|
validate(ctx) {
|
|
217
|
-
|
|
224
|
+
path2(ctx);
|
|
218
225
|
body?.(ctx);
|
|
219
226
|
},
|
|
220
227
|
dryRun(ctx) {
|
|
@@ -224,7 +231,7 @@ function command(name, description, flags, method, path, body) {
|
|
|
224
231
|
url: buildCapabilityGatewayUrl(
|
|
225
232
|
resolveApprovalApiBaseUrl(ctx.host()),
|
|
226
233
|
"agent",
|
|
227
|
-
|
|
234
|
+
path2(ctx)
|
|
228
235
|
),
|
|
229
236
|
...payload ? {
|
|
230
237
|
body: name === "send" ? { ...payload, title: "[redacted]", body: "[redacted]" } : payload
|
|
@@ -235,7 +242,7 @@ function command(name, description, flags, method, path, body) {
|
|
|
235
242
|
return callCapabilityApi(
|
|
236
243
|
ctx.host(),
|
|
237
244
|
"agent",
|
|
238
|
-
|
|
245
|
+
path2(ctx),
|
|
239
246
|
method,
|
|
240
247
|
body?.(ctx),
|
|
241
248
|
{
|
|
@@ -355,9 +362,9 @@ var notificationCommands = [
|
|
|
355
362
|
var BASE_PATH = "/api/sandbox/agent/agents";
|
|
356
363
|
function buildQuery(ctx) {
|
|
357
364
|
const params = new URLSearchParams();
|
|
358
|
-
const
|
|
365
|
+
const scope2 = ctx.str("scope");
|
|
359
366
|
const q = ctx.str("q");
|
|
360
|
-
if (
|
|
367
|
+
if (scope2) params.set("scope", scope2);
|
|
361
368
|
if (q) params.set("q", q);
|
|
362
369
|
const qs = params.toString();
|
|
363
370
|
return qs ? `?${qs}` : "";
|
|
@@ -382,8 +389,8 @@ var listAgents = {
|
|
|
382
389
|
],
|
|
383
390
|
risk: "read",
|
|
384
391
|
validate: (ctx) => {
|
|
385
|
-
const
|
|
386
|
-
if (
|
|
392
|
+
const scope2 = ctx.str("scope");
|
|
393
|
+
if (scope2 && !["personal", "company", "system"].includes(scope2)) {
|
|
387
394
|
throw new Error("--scope \u5FC5\u987B\u662F personal\u3001company \u6216 system");
|
|
388
395
|
}
|
|
389
396
|
},
|
|
@@ -422,8 +429,8 @@ var createAgent = {
|
|
|
422
429
|
if (!name || name.length < 1 || name.length > 100) {
|
|
423
430
|
throw new Error("--name length must be between 1 and 100");
|
|
424
431
|
}
|
|
425
|
-
const
|
|
426
|
-
if (
|
|
432
|
+
const scope2 = ctx.str("scope");
|
|
433
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
427
434
|
throw new Error("--scope must be personal or company");
|
|
428
435
|
}
|
|
429
436
|
},
|
|
@@ -569,8 +576,8 @@ var getAgentContext = {
|
|
|
569
576
|
],
|
|
570
577
|
risk: "read",
|
|
571
578
|
validate: (ctx) => {
|
|
572
|
-
const
|
|
573
|
-
if (!
|
|
579
|
+
const id2 = ctx.str("id");
|
|
580
|
+
if (!id2 || id2 !== id2.trim() || id2.length > 191) {
|
|
574
581
|
throw new CliValidationError("--id must be a non-empty identifier of at most 191 characters");
|
|
575
582
|
}
|
|
576
583
|
},
|
|
@@ -601,11 +608,11 @@ function requireId(ctx, key, flag2) {
|
|
|
601
608
|
}
|
|
602
609
|
return value;
|
|
603
610
|
}
|
|
604
|
-
function url(ctx,
|
|
605
|
-
return buildCapabilityGatewayUrl(resolveApprovalApiBaseUrl(ctx.host()), "agent",
|
|
611
|
+
function url(ctx, path2) {
|
|
612
|
+
return buildCapabilityGatewayUrl(resolveApprovalApiBaseUrl(ctx.host()), "agent", path2);
|
|
606
613
|
}
|
|
607
|
-
function request(ctx, method,
|
|
608
|
-
return callCapabilityApi(ctx.host(), "agent",
|
|
614
|
+
function request(ctx, method, path2, body) {
|
|
615
|
+
return callCapabilityApi(ctx.host(), "agent", path2, method, body, {
|
|
609
616
|
apiBaseUrl: resolveApprovalApiBaseUrl(ctx.host()),
|
|
610
617
|
retryOnInvalidTokenForbidden: false
|
|
611
618
|
});
|
|
@@ -647,7 +654,7 @@ var expectedVersionFlag = {
|
|
|
647
654
|
};
|
|
648
655
|
function shareBody(ctx) {
|
|
649
656
|
const recipients = ctx.json("toUserIds");
|
|
650
|
-
if (!Array.isArray(recipients) || recipients.length < 1 || recipients.length > 50 || recipients.some((
|
|
657
|
+
if (!Array.isArray(recipients) || recipients.length < 1 || recipients.length > 50 || recipients.some((id2) => typeof id2 !== "string" || !id2 || id2.trim() !== id2 || id2.length > 191) || new Set(recipients).size !== recipients.length) {
|
|
651
658
|
throw new CliValidationError(
|
|
652
659
|
"--to-user-ids must be a JSON array of 1-50 distinct non-empty user IDs"
|
|
653
660
|
);
|
|
@@ -865,22 +872,22 @@ var listModels = {
|
|
|
865
872
|
],
|
|
866
873
|
risk: "read",
|
|
867
874
|
validate: (ctx) => {
|
|
868
|
-
const
|
|
869
|
-
if (
|
|
875
|
+
const scope2 = ctx.str("scope");
|
|
876
|
+
if (scope2 && !["personal", "company", "system"].includes(scope2)) {
|
|
870
877
|
throw new Error("--scope must be personal, company, or system");
|
|
871
878
|
}
|
|
872
879
|
},
|
|
873
880
|
dryRun: (ctx) => {
|
|
874
|
-
const
|
|
881
|
+
const scope2 = ctx.str("scope");
|
|
875
882
|
const params = new URLSearchParams();
|
|
876
|
-
if (
|
|
883
|
+
if (scope2) params.set("scope", scope2);
|
|
877
884
|
const qs = params.toString();
|
|
878
885
|
return { method: "GET", url: `${BASE_PATH2}${qs ? `?${qs}` : ""}` };
|
|
879
886
|
},
|
|
880
887
|
execute: async (ctx) => {
|
|
881
|
-
const
|
|
888
|
+
const scope2 = ctx.str("scope");
|
|
882
889
|
const params = new URLSearchParams();
|
|
883
|
-
if (
|
|
890
|
+
if (scope2) params.set("scope", scope2);
|
|
884
891
|
const qs = params.toString();
|
|
885
892
|
const current = process.env.TE_AGENT_CURRENT_MODEL_ID?.trim();
|
|
886
893
|
const data = await getAgentApi(
|
|
@@ -944,8 +951,8 @@ var addModel = {
|
|
|
944
951
|
} catch {
|
|
945
952
|
throw new Error("--base-url must be a valid URL");
|
|
946
953
|
}
|
|
947
|
-
const
|
|
948
|
-
if (
|
|
954
|
+
const scope2 = ctx.str("scope");
|
|
955
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
949
956
|
throw new Error("--scope must be personal or company");
|
|
950
957
|
}
|
|
951
958
|
},
|
|
@@ -997,19 +1004,19 @@ var delModel = {
|
|
|
997
1004
|
],
|
|
998
1005
|
risk: "high-risk-write",
|
|
999
1006
|
validate: (ctx) => {
|
|
1000
|
-
const
|
|
1001
|
-
if (
|
|
1007
|
+
const scope2 = ctx.str("scope");
|
|
1008
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
1002
1009
|
throw new Error("--scope must be personal or company");
|
|
1003
1010
|
}
|
|
1004
1011
|
},
|
|
1005
1012
|
dryRun: (ctx) => {
|
|
1006
|
-
const
|
|
1007
|
-
const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(
|
|
1013
|
+
const scope2 = ctx.str("scope") || "personal";
|
|
1014
|
+
const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(scope2)}`;
|
|
1008
1015
|
return { method: "DELETE", url: `${BASE_PATH2}?${qs}` };
|
|
1009
1016
|
},
|
|
1010
1017
|
execute: async (ctx) => {
|
|
1011
|
-
const
|
|
1012
|
-
const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(
|
|
1018
|
+
const scope2 = ctx.str("scope") || "personal";
|
|
1019
|
+
const qs = `id=${encodeURIComponent(ctx.str("id"))}&scope=${encodeURIComponent(scope2)}`;
|
|
1013
1020
|
return deleteAgentApi(ctx, `${BASE_PATH2}?${qs}`);
|
|
1014
1021
|
}
|
|
1015
1022
|
};
|
|
@@ -1069,8 +1076,8 @@ var updateModel = {
|
|
|
1069
1076
|
} catch {
|
|
1070
1077
|
throw new Error("--base-url must be a valid URL");
|
|
1071
1078
|
}
|
|
1072
|
-
const
|
|
1073
|
-
if (
|
|
1079
|
+
const scope2 = ctx.str("scope");
|
|
1080
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
1074
1081
|
throw new Error("--scope must be personal or company");
|
|
1075
1082
|
}
|
|
1076
1083
|
},
|
|
@@ -1144,8 +1151,8 @@ var testModel = {
|
|
|
1144
1151
|
if (apiKey) body.apiKey = apiKey;
|
|
1145
1152
|
const provider = ctx.str("provider");
|
|
1146
1153
|
if (provider) body.provider = provider;
|
|
1147
|
-
const
|
|
1148
|
-
if (
|
|
1154
|
+
const id2 = ctx.str("id");
|
|
1155
|
+
if (id2) body.existingConfigId = id2;
|
|
1149
1156
|
return { method: "POST", url: `${BASE_PATH2}/test`, body };
|
|
1150
1157
|
},
|
|
1151
1158
|
execute: async (ctx) => {
|
|
@@ -1157,8 +1164,8 @@ var testModel = {
|
|
|
1157
1164
|
if (apiKey) body.apiKey = apiKey;
|
|
1158
1165
|
const provider = ctx.str("provider");
|
|
1159
1166
|
if (provider) body.provider = provider;
|
|
1160
|
-
const
|
|
1161
|
-
if (
|
|
1167
|
+
const id2 = ctx.str("id");
|
|
1168
|
+
if (id2) body.existingConfigId = id2;
|
|
1162
1169
|
return postAgentApi(ctx, `${BASE_PATH2}/test`, body);
|
|
1163
1170
|
}
|
|
1164
1171
|
};
|
|
@@ -1220,19 +1227,19 @@ var listMcps = {
|
|
|
1220
1227
|
],
|
|
1221
1228
|
risk: "read",
|
|
1222
1229
|
validate: (ctx) => {
|
|
1223
|
-
const
|
|
1224
|
-
if (
|
|
1230
|
+
const scope2 = ctx.str("scope");
|
|
1231
|
+
if (scope2 && !["personal", "company", "system"].includes(scope2)) {
|
|
1225
1232
|
throw new Error("--scope must be personal, company, or system");
|
|
1226
1233
|
}
|
|
1227
1234
|
},
|
|
1228
1235
|
dryRun: (ctx) => {
|
|
1229
|
-
const
|
|
1230
|
-
const qs =
|
|
1236
|
+
const scope2 = ctx.str("scope");
|
|
1237
|
+
const qs = scope2 ? `?scope=${encodeURIComponent(scope2)}` : "";
|
|
1231
1238
|
return { method: "GET", url: `${BASE_PATH3}${qs}` };
|
|
1232
1239
|
},
|
|
1233
1240
|
execute: async (ctx) => {
|
|
1234
|
-
const
|
|
1235
|
-
const qs =
|
|
1241
|
+
const scope2 = ctx.str("scope");
|
|
1242
|
+
const qs = scope2 ? `?scope=${encodeURIComponent(scope2)}` : "";
|
|
1236
1243
|
return getAgentApi(ctx, `${BASE_PATH3}${qs}`);
|
|
1237
1244
|
}
|
|
1238
1245
|
};
|
|
@@ -1277,8 +1284,8 @@ var addMcp = {
|
|
|
1277
1284
|
if (category && !isValidMarketCategory(category)) {
|
|
1278
1285
|
throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
|
|
1279
1286
|
}
|
|
1280
|
-
const
|
|
1281
|
-
if (
|
|
1287
|
+
const scope2 = ctx.str("scope");
|
|
1288
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
1282
1289
|
throw new Error("--scope must be personal or company");
|
|
1283
1290
|
}
|
|
1284
1291
|
},
|
|
@@ -1306,11 +1313,11 @@ var addMcp = {
|
|
|
1306
1313
|
headers: ctx.json("headers") || void 0,
|
|
1307
1314
|
scope: ctx.str("scope") || "personal"
|
|
1308
1315
|
});
|
|
1309
|
-
const
|
|
1316
|
+
const id2 = created?.item?.id;
|
|
1310
1317
|
const meta = buildMetaBody(ctx);
|
|
1311
|
-
if (
|
|
1318
|
+
if (id2 && meta) {
|
|
1312
1319
|
try {
|
|
1313
|
-
await patchAgentApi(ctx, `${MARKET_BASE_PATH}/${encodeURIComponent(
|
|
1320
|
+
await patchAgentApi(ctx, `${MARKET_BASE_PATH}/${encodeURIComponent(id2)}/meta`, meta);
|
|
1314
1321
|
} catch (err) {
|
|
1315
1322
|
process.stderr.write(`Warning: MCP created but meta update failed: ${err?.message ?? err}
|
|
1316
1323
|
`);
|
|
@@ -1370,8 +1377,8 @@ var listMcpMarket = {
|
|
|
1370
1377
|
],
|
|
1371
1378
|
risk: "read",
|
|
1372
1379
|
validate: (ctx) => {
|
|
1373
|
-
const
|
|
1374
|
-
if (
|
|
1380
|
+
const scope2 = ctx.str("scope");
|
|
1381
|
+
if (scope2 && !MARKET_SCOPES.includes(scope2)) {
|
|
1375
1382
|
throw new Error(`--scope must be one of: ${MARKET_SCOPES.join(", ")}`);
|
|
1376
1383
|
}
|
|
1377
1384
|
const category = ctx.str("category");
|
|
@@ -1558,14 +1565,14 @@ var mcpAuthStart = {
|
|
|
1558
1565
|
}
|
|
1559
1566
|
);
|
|
1560
1567
|
if (result?.authorizeUrl && (process.stderr.isTTY || process.stdout.isTTY)) {
|
|
1561
|
-
const
|
|
1568
|
+
const id2 = ctx.str("id");
|
|
1562
1569
|
process.stderr.write(
|
|
1563
1570
|
`
|
|
1564
1571
|
\u8BF7\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u4EE5\u4E0B URL \u5B8C\u6210\u6388\u6743\uFF1A
|
|
1565
1572
|
${result.authorizeUrl}
|
|
1566
1573
|
|
|
1567
1574
|
\u6388\u6743\u5B8C\u6210\u540E\uFF0C\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u8F6E\u8BE2\u6388\u6743\u72B6\u6001\uFF1A
|
|
1568
|
-
ae-cli agent +mcp-auth-status --id ${
|
|
1575
|
+
ae-cli agent +mcp-auth-status --id ${id2}
|
|
1569
1576
|
|
|
1570
1577
|
`
|
|
1571
1578
|
);
|
|
@@ -1752,19 +1759,19 @@ var listSkills = {
|
|
|
1752
1759
|
],
|
|
1753
1760
|
risk: "read",
|
|
1754
1761
|
validate: (ctx) => {
|
|
1755
|
-
const
|
|
1756
|
-
if (
|
|
1762
|
+
const scope2 = ctx.str("scope");
|
|
1763
|
+
if (scope2 && !["personal", "company", "system"].includes(scope2)) {
|
|
1757
1764
|
throw new Error("--scope must be personal, company, or system");
|
|
1758
1765
|
}
|
|
1759
1766
|
},
|
|
1760
1767
|
dryRun: (ctx) => {
|
|
1761
|
-
const
|
|
1762
|
-
const qs =
|
|
1768
|
+
const scope2 = ctx.str("scope");
|
|
1769
|
+
const qs = scope2 ? `?scope=${encodeURIComponent(scope2)}` : "";
|
|
1763
1770
|
return { method: "GET", url: `${BASE_PATH4}${qs}` };
|
|
1764
1771
|
},
|
|
1765
1772
|
execute: async (ctx) => {
|
|
1766
|
-
const
|
|
1767
|
-
const qs =
|
|
1773
|
+
const scope2 = ctx.str("scope");
|
|
1774
|
+
const qs = scope2 ? `?scope=${encodeURIComponent(scope2)}` : "";
|
|
1768
1775
|
return getAgentApi(ctx, `${BASE_PATH4}${qs}`);
|
|
1769
1776
|
}
|
|
1770
1777
|
};
|
|
@@ -1839,8 +1846,8 @@ var addSkill = {
|
|
|
1839
1846
|
if (category && !isValidMarketCategory(category)) {
|
|
1840
1847
|
throw new Error(`--category must be one of: ${MARKET_CATEGORIES.join(", ")}`);
|
|
1841
1848
|
}
|
|
1842
|
-
const
|
|
1843
|
-
if (
|
|
1849
|
+
const scope2 = ctx.str("scope");
|
|
1850
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
1844
1851
|
throw new Error("--scope must be personal or company");
|
|
1845
1852
|
}
|
|
1846
1853
|
const version = ctx.str("version");
|
|
@@ -1869,11 +1876,11 @@ var addSkill = {
|
|
|
1869
1876
|
scope: ctx.str("scope") || "personal",
|
|
1870
1877
|
version: ctx.str("version") || void 0
|
|
1871
1878
|
});
|
|
1872
|
-
const
|
|
1879
|
+
const id2 = created?.item?.id;
|
|
1873
1880
|
const meta = buildMetaBody2(ctx);
|
|
1874
|
-
if (
|
|
1881
|
+
if (id2 && meta) {
|
|
1875
1882
|
try {
|
|
1876
|
-
await patchAgentApi(ctx, `${MARKET_BASE_PATH2}/${encodeURIComponent(
|
|
1883
|
+
await patchAgentApi(ctx, `${MARKET_BASE_PATH2}/${encodeURIComponent(id2)}/meta`, meta);
|
|
1877
1884
|
} catch (err) {
|
|
1878
1885
|
process.stderr.write(`Warning: Skill created but meta update failed: ${err?.message ?? err}
|
|
1879
1886
|
`);
|
|
@@ -1982,8 +1989,8 @@ var listSkillMarket = {
|
|
|
1982
1989
|
],
|
|
1983
1990
|
risk: "read",
|
|
1984
1991
|
validate: (ctx) => {
|
|
1985
|
-
const
|
|
1986
|
-
if (
|
|
1992
|
+
const scope2 = ctx.str("scope");
|
|
1993
|
+
if (scope2 && !MARKET_SCOPES.includes(scope2)) {
|
|
1987
1994
|
throw new Error(`--scope must be one of: ${MARKET_SCOPES.join(", ")}`);
|
|
1988
1995
|
}
|
|
1989
1996
|
const category = ctx.str("category");
|
|
@@ -2594,8 +2601,8 @@ var uploadSkill = {
|
|
|
2594
2601
|
if (!existsSync(resolved)) throw new Error(`File not found: ${resolved}`);
|
|
2595
2602
|
const ext = extname(resolved).toLowerCase();
|
|
2596
2603
|
if (ext !== ".zip") throw new Error("--file must be a .zip file");
|
|
2597
|
-
const
|
|
2598
|
-
if (
|
|
2604
|
+
const scope2 = ctx.str("scope");
|
|
2605
|
+
if (scope2 && !["personal", "company"].includes(scope2)) {
|
|
2599
2606
|
throw new Error("--scope must be personal or company");
|
|
2600
2607
|
}
|
|
2601
2608
|
const category = ctx.str("category");
|
|
@@ -2640,8 +2647,8 @@ var uploadSkill = {
|
|
|
2640
2647
|
type: "application/zip"
|
|
2641
2648
|
});
|
|
2642
2649
|
fd.append("file", blob, fileName);
|
|
2643
|
-
const
|
|
2644
|
-
fd.append("scope",
|
|
2650
|
+
const scope2 = ctx.str("scope") || "personal";
|
|
2651
|
+
fd.append("scope", scope2);
|
|
2645
2652
|
if (ctx.bool("autoRename")) fd.append("autoRename", "true");
|
|
2646
2653
|
if (ctx.str("replaceSkillId")) fd.append("replaceSkillId", ctx.str("replaceSkillId"));
|
|
2647
2654
|
if (ctx.str("category")) fd.append("category", ctx.str("category"));
|
|
@@ -3121,12 +3128,12 @@ function parseShim(filePath) {
|
|
|
3121
3128
|
target: ""
|
|
3122
3129
|
};
|
|
3123
3130
|
try {
|
|
3124
|
-
const
|
|
3125
|
-
if (!
|
|
3126
|
-
const lines = readShimHeader(filePath,
|
|
3131
|
+
const stat2 = lstatSync(filePath);
|
|
3132
|
+
if (!stat2.isFile() || stat2.isSymbolicLink()) return fallback;
|
|
3133
|
+
const lines = readShimHeader(filePath, stat2.size).split("\n").slice(0, 10);
|
|
3127
3134
|
const managed = lines.includes(`# ${SHIM_MARKER}`);
|
|
3128
3135
|
if (!managed) return fallback;
|
|
3129
|
-
if (
|
|
3136
|
+
if (stat2.size > MAX_SHIM_BYTES) {
|
|
3130
3137
|
return { ...fallback, managed: true, reason: "shim exceeds size limit" };
|
|
3131
3138
|
}
|
|
3132
3139
|
const values = /* @__PURE__ */ new Map();
|
|
@@ -3578,17 +3585,17 @@ function validateLimit(ctx) {
|
|
|
3578
3585
|
function isRecord(value) {
|
|
3579
3586
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3580
3587
|
}
|
|
3581
|
-
function validateSnakeCaseValue(value,
|
|
3588
|
+
function validateSnakeCaseValue(value, path2 = "payload") {
|
|
3582
3589
|
if (Array.isArray(value)) {
|
|
3583
|
-
value.forEach((item, index) => validateSnakeCaseValue(item, `${
|
|
3590
|
+
value.forEach((item, index) => validateSnakeCaseValue(item, `${path2}[${index}]`));
|
|
3584
3591
|
return;
|
|
3585
3592
|
}
|
|
3586
3593
|
if (!isRecord(value)) return;
|
|
3587
3594
|
for (const [key, child] of Object.entries(value)) {
|
|
3588
3595
|
if (!/^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/.test(key)) {
|
|
3589
|
-
validation(`--payload keys must use snake_case (invalid key at ${
|
|
3596
|
+
validation(`--payload keys must use snake_case (invalid key at ${path2})`);
|
|
3590
3597
|
}
|
|
3591
|
-
validateSnakeCaseValue(child, `${
|
|
3598
|
+
validateSnakeCaseValue(child, `${path2}.${key}`);
|
|
3592
3599
|
}
|
|
3593
3600
|
}
|
|
3594
3601
|
function approvalPayload(ctx) {
|
|
@@ -4013,6 +4020,649 @@ var retryApprovalEffect = {
|
|
|
4013
4020
|
)
|
|
4014
4021
|
};
|
|
4015
4022
|
|
|
4023
|
+
// src/commands/te-agent/resource-packages.ts
|
|
4024
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
4025
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
4026
|
+
|
|
4027
|
+
// src/commands/te-agent/resource-package-transfer.ts
|
|
4028
|
+
import { createHash, randomUUID } from "crypto";
|
|
4029
|
+
import { createReadStream, createWriteStream } from "fs";
|
|
4030
|
+
import { chmod, link, lstat, mkdir, open, readFile, rename, stat, unlink, writeFile } from "fs/promises";
|
|
4031
|
+
import path from "path";
|
|
4032
|
+
import { Readable } from "stream";
|
|
4033
|
+
import { pipeline } from "stream/promises";
|
|
4034
|
+
function stateDirectory() {
|
|
4035
|
+
return path.join(getConfigDir(), "transfers", "resource-packages");
|
|
4036
|
+
}
|
|
4037
|
+
async function ensureDirectory(directory) {
|
|
4038
|
+
await mkdir(directory, { recursive: true, mode: 448 });
|
|
4039
|
+
await chmod(directory, 448);
|
|
4040
|
+
}
|
|
4041
|
+
async function saveJson(filePath, data) {
|
|
4042
|
+
const temporary = `${filePath}.${process.pid}.tmp`;
|
|
4043
|
+
await writeFile(temporary, `${JSON.stringify(data)}
|
|
4044
|
+
`, { mode: 384 });
|
|
4045
|
+
await chmod(temporary, 384);
|
|
4046
|
+
await rename(temporary, filePath);
|
|
4047
|
+
}
|
|
4048
|
+
async function loadJson(filePath) {
|
|
4049
|
+
try {
|
|
4050
|
+
const info = await lstat(filePath);
|
|
4051
|
+
if (!info.isFile() || info.isSymbolicLink()) throw new Error(`Unsafe transfer metadata: ${filePath}`);
|
|
4052
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
4053
|
+
} catch (error) {
|
|
4054
|
+
if (error.code === "ENOENT") return void 0;
|
|
4055
|
+
throw new Error(`Invalid transfer metadata: ${filePath}`);
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
async function removeFile(filePath) {
|
|
4059
|
+
try {
|
|
4060
|
+
await unlink(filePath);
|
|
4061
|
+
} catch (error) {
|
|
4062
|
+
if (error.code !== "ENOENT") throw error;
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
function sameIdentity(left, right) {
|
|
4066
|
+
return left.size === right.size && left.mtimeMs === right.mtimeMs && left.dev === right.dev && left.ino === right.ino;
|
|
4067
|
+
}
|
|
4068
|
+
function statePath(directory, host, filePath, scope2) {
|
|
4069
|
+
const key = createHash("sha256").update(`${host}\0${filePath}\0${scope2}`).digest("hex");
|
|
4070
|
+
return path.join(directory, `upload-${key}.json`);
|
|
4071
|
+
}
|
|
4072
|
+
async function slice(filePath, offset, length) {
|
|
4073
|
+
const file = await open(filePath, "r");
|
|
4074
|
+
try {
|
|
4075
|
+
const bytes = Buffer.allocUnsafe(length);
|
|
4076
|
+
const result = await file.read(bytes, 0, length, offset);
|
|
4077
|
+
if (result.bytesRead !== length) throw new Error("The resource package file changed during upload");
|
|
4078
|
+
return bytes;
|
|
4079
|
+
} finally {
|
|
4080
|
+
await file.close();
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
async function transientRetry(operation, maxAttempts) {
|
|
4084
|
+
for (let attempt = 0; ; attempt += 1) {
|
|
4085
|
+
try {
|
|
4086
|
+
return await operation();
|
|
4087
|
+
} catch (error) {
|
|
4088
|
+
const transient = isTransientResourcePackageError(error);
|
|
4089
|
+
if (!transient || attempt + 1 >= maxAttempts) throw error;
|
|
4090
|
+
await new Promise((resolve4) => setTimeout(resolve4, 250 * 2 ** attempt));
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
async function uploadPackage(ctx, input) {
|
|
4095
|
+
const absolute = path.resolve(input.filePath);
|
|
4096
|
+
const before = await lstat(absolute).catch(() => void 0);
|
|
4097
|
+
if (!before?.isFile() || before.isSymbolicLink() || before.size < 1 || path.extname(absolute).toLowerCase() !== ".zip") {
|
|
4098
|
+
throw new Error("--file must point to a non-empty regular .zip file");
|
|
4099
|
+
}
|
|
4100
|
+
const directory = input.stateRoot ?? stateDirectory();
|
|
4101
|
+
await ensureDirectory(directory);
|
|
4102
|
+
const savedPath = statePath(directory, ctx.host(), absolute, input.scope);
|
|
4103
|
+
let saved = await loadJson(savedPath);
|
|
4104
|
+
if (saved && (!sameIdentity(saved, before) || saved.host !== ctx.host() || saved.scope !== input.scope)) {
|
|
4105
|
+
await removeFile(savedPath);
|
|
4106
|
+
saved = void 0;
|
|
4107
|
+
}
|
|
4108
|
+
let upload;
|
|
4109
|
+
const candidate = input.uploadId || saved?.uploadId;
|
|
4110
|
+
if (candidate) {
|
|
4111
|
+
try {
|
|
4112
|
+
upload = await requestResourcePackageApi(
|
|
4113
|
+
ctx,
|
|
4114
|
+
"GET",
|
|
4115
|
+
`/api/resource-packages/uploads/${encodeURIComponent(candidate)}`
|
|
4116
|
+
);
|
|
4117
|
+
} catch (error) {
|
|
4118
|
+
if (input.uploadId || !(error instanceof TeAgentApiError) || error.status !== 404 && error.status !== 410 && error.code !== "UPLOAD_EXPIRED") throw error;
|
|
4119
|
+
await removeFile(savedPath);
|
|
4120
|
+
saved = void 0;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
if (upload && (upload.fileName !== path.basename(absolute) || upload.totalBytes !== before.size || upload.scope !== input.scope || !["uploading", "completed"].includes(upload.status))) {
|
|
4124
|
+
if (input.uploadId) throw new Error("--upload-id does not match the selected ZIP and scope");
|
|
4125
|
+
upload = void 0;
|
|
4126
|
+
await removeFile(savedPath);
|
|
4127
|
+
}
|
|
4128
|
+
if (!upload) {
|
|
4129
|
+
upload = await requestResourcePackageApi(ctx, "POST", "/api/resource-packages/uploads", {
|
|
4130
|
+
fileName: path.basename(absolute),
|
|
4131
|
+
totalBytes: before.size,
|
|
4132
|
+
scope: input.scope
|
|
4133
|
+
});
|
|
4134
|
+
}
|
|
4135
|
+
if (!upload) throw new Error("The service did not create an upload");
|
|
4136
|
+
const active = upload;
|
|
4137
|
+
if (saved?.requestKey && input.requestKey && saved.requestKey !== input.requestKey) {
|
|
4138
|
+
throw new Error("--request-key differs from the existing upload state; reuse its original key");
|
|
4139
|
+
}
|
|
4140
|
+
const requestKey = input.requestKey || saved?.requestKey || randomUUID();
|
|
4141
|
+
const trustedLocalState = Boolean(saved && saved.uploadId === active.id && sameIdentity(saved, before));
|
|
4142
|
+
const state = {
|
|
4143
|
+
version: 1,
|
|
4144
|
+
host: ctx.host(),
|
|
4145
|
+
filePath: absolute,
|
|
4146
|
+
scope: input.scope,
|
|
4147
|
+
uploadId: active.id,
|
|
4148
|
+
size: before.size,
|
|
4149
|
+
mtimeMs: before.mtimeMs,
|
|
4150
|
+
dev: before.dev,
|
|
4151
|
+
ino: before.ino,
|
|
4152
|
+
requestKey
|
|
4153
|
+
};
|
|
4154
|
+
await saveJson(savedPath, state);
|
|
4155
|
+
if (active.status === "uploading") {
|
|
4156
|
+
const limits = await requestResourcePackageApi(
|
|
4157
|
+
ctx,
|
|
4158
|
+
"GET",
|
|
4159
|
+
"/api/resource-packages/limits"
|
|
4160
|
+
);
|
|
4161
|
+
const concurrency = Math.max(1, Math.min(8, limits.desktopUploadConcurrency || 3));
|
|
4162
|
+
const maxAttempts = Math.max(1, Math.min(10, limits.uploadChunkRetries || 3));
|
|
4163
|
+
const done = new Set(active.parts ?? []);
|
|
4164
|
+
const pending = Array.from({ length: active.totalChunks }, (_, index) => index).filter((index) => !trustedLocalState || !done.has(index));
|
|
4165
|
+
let next = 0;
|
|
4166
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, pending.length) }, async () => {
|
|
4167
|
+
while (next < pending.length) {
|
|
4168
|
+
const part = pending[next++];
|
|
4169
|
+
const offset = part * active.chunkBytes;
|
|
4170
|
+
const bytes = await slice(absolute, offset, Math.min(active.chunkBytes, before.size - offset));
|
|
4171
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
4172
|
+
await transientRetry(async () => {
|
|
4173
|
+
const response = await requestResourcePackageRaw(
|
|
4174
|
+
ctx,
|
|
4175
|
+
"PUT",
|
|
4176
|
+
`/api/resource-packages/uploads/${encodeURIComponent(active.id)}/chunks/${part}`,
|
|
4177
|
+
{
|
|
4178
|
+
body: new Uint8Array(bytes),
|
|
4179
|
+
timeoutMs: 12e4,
|
|
4180
|
+
headers: {
|
|
4181
|
+
"Content-Type": "application/octet-stream",
|
|
4182
|
+
"Content-Length": String(bytes.length),
|
|
4183
|
+
"X-Chunk-Sha256": digest
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
);
|
|
4187
|
+
await response.body?.cancel();
|
|
4188
|
+
}, maxAttempts);
|
|
4189
|
+
}
|
|
4190
|
+
}));
|
|
4191
|
+
}
|
|
4192
|
+
const after = await stat(absolute);
|
|
4193
|
+
if (!sameIdentity(before, after)) {
|
|
4194
|
+
throw new Error("The resource package file changed during upload; retry with the unchanged ZIP");
|
|
4195
|
+
}
|
|
4196
|
+
const completed = await requestResourcePackageApi(
|
|
4197
|
+
ctx,
|
|
4198
|
+
"POST",
|
|
4199
|
+
`/api/resource-packages/uploads/${encodeURIComponent(active.id)}/complete`,
|
|
4200
|
+
{}
|
|
4201
|
+
);
|
|
4202
|
+
return { completed, statePath: savedPath, requestKey };
|
|
4203
|
+
}
|
|
4204
|
+
async function clearUploadState(filePath) {
|
|
4205
|
+
await removeFile(filePath);
|
|
4206
|
+
}
|
|
4207
|
+
function artifactFileName(response) {
|
|
4208
|
+
const disposition = response.headers.get("content-disposition") || "";
|
|
4209
|
+
const encoded = disposition.match(/filename\*=UTF-8''([^;]+)/i)?.[1];
|
|
4210
|
+
if (encoded) {
|
|
4211
|
+
try {
|
|
4212
|
+
return path.basename(decodeURIComponent(encoded.trim()));
|
|
4213
|
+
} catch {
|
|
4214
|
+
return path.basename(encoded.trim());
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
const ordinary = disposition.match(/filename="([^"]+)"/i)?.[1] ?? disposition.match(/filename=([^;]+)/i)?.[1];
|
|
4218
|
+
return ordinary ? path.basename(ordinary.trim()) : void 0;
|
|
4219
|
+
}
|
|
4220
|
+
async function fileHash(filePath) {
|
|
4221
|
+
const hash = createHash("sha256");
|
|
4222
|
+
for await (const chunk of createReadStream(filePath)) hash.update(chunk);
|
|
4223
|
+
return hash.digest("hex");
|
|
4224
|
+
}
|
|
4225
|
+
async function downloadArtifact(ctx, task, outputPath, timezone) {
|
|
4226
|
+
const query2 = timezone ? `?timezone=${encodeURIComponent(timezone)}` : "";
|
|
4227
|
+
const url2 = `/api/resource-packages/tasks/${encodeURIComponent(task.id)}/artifact${query2}`;
|
|
4228
|
+
const head = await requestResourcePackageRaw(ctx, "HEAD", url2);
|
|
4229
|
+
const totalBytes = Number(head.headers.get("content-length"));
|
|
4230
|
+
if (!Number.isSafeInteger(totalBytes) || totalBytes < 1) throw new Error("Artifact Content-Length is invalid");
|
|
4231
|
+
const etag = head.headers.get("etag") || "";
|
|
4232
|
+
const output = path.resolve(outputPath ?? artifactFileName(head) ?? `resource-package-${task.id}.zip`);
|
|
4233
|
+
try {
|
|
4234
|
+
await lstat(output);
|
|
4235
|
+
throw new Error(`Output file already exists: ${output}`);
|
|
4236
|
+
} catch (error) {
|
|
4237
|
+
if (error.code !== "ENOENT") throw error;
|
|
4238
|
+
}
|
|
4239
|
+
const partial = `${output}.part`;
|
|
4240
|
+
const metadataPath = `${partial}.json`;
|
|
4241
|
+
let offset = 0;
|
|
4242
|
+
try {
|
|
4243
|
+
const info2 = await lstat(partial);
|
|
4244
|
+
if (!info2.isFile() || info2.isSymbolicLink()) throw new Error(`Unsafe partial file: ${partial}`);
|
|
4245
|
+
const metadata = await loadJson(metadataPath);
|
|
4246
|
+
if (!etag || !metadata || metadata.host !== ctx.host() || metadata.taskId !== task.id || metadata.etag !== etag || metadata.totalBytes !== totalBytes || info2.size > totalBytes) {
|
|
4247
|
+
throw new Error(`Partial artifact cannot be resumed safely: ${partial}`);
|
|
4248
|
+
}
|
|
4249
|
+
offset = info2.size;
|
|
4250
|
+
} catch (error) {
|
|
4251
|
+
if (error.code !== "ENOENT") throw error;
|
|
4252
|
+
}
|
|
4253
|
+
if (offset === 0) {
|
|
4254
|
+
await saveJson(metadataPath, { version: 1, host: ctx.host(), taskId: task.id, etag, totalBytes });
|
|
4255
|
+
}
|
|
4256
|
+
if (offset < totalBytes) {
|
|
4257
|
+
const response = await requestResourcePackageRaw(ctx, "GET", url2, {
|
|
4258
|
+
headers: offset ? { Range: `bytes=${offset}-`, "If-Range": etag } : void 0,
|
|
4259
|
+
timeoutMs: 12e4
|
|
4260
|
+
});
|
|
4261
|
+
if (offset && response.status !== 206 || !offset && response.status !== 200) {
|
|
4262
|
+
throw new Error("Artifact server returned an unexpected range status");
|
|
4263
|
+
}
|
|
4264
|
+
if (etag && response.headers.get("etag") !== etag) throw new Error("Artifact changed while downloading");
|
|
4265
|
+
if (offset && response.headers.get("content-range") !== `bytes ${offset}-${totalBytes - 1}/${totalBytes}`) {
|
|
4266
|
+
throw new Error("Artifact server returned a mismatched Content-Range");
|
|
4267
|
+
}
|
|
4268
|
+
if (!response.body) throw new Error("Artifact response body is empty");
|
|
4269
|
+
await pipeline(
|
|
4270
|
+
Readable.fromWeb(response.body),
|
|
4271
|
+
createWriteStream(partial, { flags: offset ? "a" : "wx", mode: 384 })
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
const info = await stat(partial);
|
|
4275
|
+
if (info.size !== totalBytes) throw new Error(`Artifact size mismatch: expected ${totalBytes}, got ${info.size}`);
|
|
4276
|
+
const sha256 = await fileHash(partial);
|
|
4277
|
+
if (!task.packageSha256 || !/^[a-f0-9]{64}$/.test(task.packageSha256)) {
|
|
4278
|
+
throw new Error("Export task does not provide a valid package SHA-256 for verification");
|
|
4279
|
+
}
|
|
4280
|
+
if (sha256 !== task.packageSha256) {
|
|
4281
|
+
throw new Error(`Artifact SHA-256 mismatch: expected ${task.packageSha256}, got ${sha256}`);
|
|
4282
|
+
}
|
|
4283
|
+
await link(partial, output);
|
|
4284
|
+
await removeFile(partial);
|
|
4285
|
+
await removeFile(metadataPath);
|
|
4286
|
+
return { path: output, bytes: totalBytes, sha256 };
|
|
4287
|
+
}
|
|
4288
|
+
|
|
4289
|
+
// src/commands/te-agent/resource-packages.ts
|
|
4290
|
+
var statuses = /* @__PURE__ */ new Set([
|
|
4291
|
+
"uploading",
|
|
4292
|
+
"preflighting",
|
|
4293
|
+
"ready",
|
|
4294
|
+
"queued",
|
|
4295
|
+
"running",
|
|
4296
|
+
"cancelling",
|
|
4297
|
+
"succeeded",
|
|
4298
|
+
"partially_succeeded",
|
|
4299
|
+
"failed",
|
|
4300
|
+
"cancelled",
|
|
4301
|
+
"cancel_failed"
|
|
4302
|
+
]);
|
|
4303
|
+
var terminal = /* @__PURE__ */ new Set(["succeeded", "partially_succeeded", "failed", "cancelled", "cancel_failed"]);
|
|
4304
|
+
var resourceTypes = /* @__PURE__ */ new Set(["knowledge_base", "mcp", "skill", "agent", "team"]);
|
|
4305
|
+
var previewNote = "Dry-run previews the local request only; it does not check permissions or current resources.";
|
|
4306
|
+
function id(ctx, key, flag2) {
|
|
4307
|
+
const value = ctx.str(key);
|
|
4308
|
+
if (!value || value.trim() !== value || value.length > 191) {
|
|
4309
|
+
throw new CliValidationError(`--${flag2} must be a non-empty identifier of at most 191 characters`);
|
|
4310
|
+
}
|
|
4311
|
+
return value;
|
|
4312
|
+
}
|
|
4313
|
+
function scope(ctx) {
|
|
4314
|
+
const value = ctx.str("scope");
|
|
4315
|
+
if (value !== "personal" && value !== "company") {
|
|
4316
|
+
throw new CliValidationError("--scope must be personal or company");
|
|
4317
|
+
}
|
|
4318
|
+
return value;
|
|
4319
|
+
}
|
|
4320
|
+
function jsonSource(raw, flag2) {
|
|
4321
|
+
if (!raw) throw new CliValidationError(`--${flag2} is required`);
|
|
4322
|
+
try {
|
|
4323
|
+
const text = raw === "-" ? readFileSync3(0, "utf8") : raw.startsWith("@") ? readFileSync3(raw.slice(1), "utf8") : raw;
|
|
4324
|
+
return JSON.parse(text);
|
|
4325
|
+
} catch (error) {
|
|
4326
|
+
throw new CliValidationError(`--${flag2} must contain valid JSON, @file JSON, or - for stdin: ${error.message}`);
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
function references(ctx, key) {
|
|
4330
|
+
const raw = ctx.str(key);
|
|
4331
|
+
if (!raw && key === "excluded") return [];
|
|
4332
|
+
const value = jsonSource(raw, key);
|
|
4333
|
+
const maximum = key === "roots" ? 500 : 2e3;
|
|
4334
|
+
if (!Array.isArray(value) || key === "roots" && !value.length || value.length > maximum || value.some((entry) => !entry || typeof entry !== "object" || Array.isArray(entry) || Object.keys(entry).sort().join(",") !== "sourceId,type" || !resourceTypes.has(entry.type) || typeof entry.sourceId !== "string" || !entry.sourceId || entry.sourceId.length > 191)) {
|
|
4335
|
+
throw new CliValidationError(`--${key} must be a JSON array of valid resource references (max ${maximum})`);
|
|
4336
|
+
}
|
|
4337
|
+
return value;
|
|
4338
|
+
}
|
|
4339
|
+
function stringArray(ctx, key, flag2) {
|
|
4340
|
+
const raw = ctx.str(key);
|
|
4341
|
+
if (!raw) return [];
|
|
4342
|
+
const value = jsonSource(raw, flag2);
|
|
4343
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
4344
|
+
throw new CliValidationError(`--${flag2} must be a JSON string array`);
|
|
4345
|
+
}
|
|
4346
|
+
return value;
|
|
4347
|
+
}
|
|
4348
|
+
function replacementMap(ctx) {
|
|
4349
|
+
const raw = ctx.str("systemReplacements");
|
|
4350
|
+
if (!raw) return {};
|
|
4351
|
+
const value = jsonSource(raw, "system-replacements");
|
|
4352
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.entries(value).length > 500 || Object.entries(value).some(([key, target]) => !key || key.length > 64 || typeof target !== "string" || !target || target.length > 191)) {
|
|
4353
|
+
throw new CliValidationError("--system-replacements must be a JSON object of reference keys to target IDs");
|
|
4354
|
+
}
|
|
4355
|
+
return value;
|
|
4356
|
+
}
|
|
4357
|
+
function taskPath(ctx) {
|
|
4358
|
+
return `/api/resource-packages/tasks/${encodeURIComponent(id(ctx, "taskId", "task-id"))}`;
|
|
4359
|
+
}
|
|
4360
|
+
function waitSettings(ctx) {
|
|
4361
|
+
const seconds = ctx.optionalNum("waitTimeoutSeconds") ?? 1800;
|
|
4362
|
+
const pollMs = ctx.optionalNum("pollIntervalMs") ?? 1500;
|
|
4363
|
+
if (!Number.isInteger(seconds) || seconds < 1 || seconds > 86400) {
|
|
4364
|
+
throw new CliValidationError("--wait-timeout-seconds must be an integer from 1 to 86400");
|
|
4365
|
+
}
|
|
4366
|
+
if (!Number.isInteger(pollMs) || pollMs < 250 || pollMs > 6e4) {
|
|
4367
|
+
throw new CliValidationError("--poll-interval-ms must be an integer from 250 to 60000");
|
|
4368
|
+
}
|
|
4369
|
+
return { timeoutMs: seconds * 1e3, pollMs };
|
|
4370
|
+
}
|
|
4371
|
+
async function waitForTask(ctx, task) {
|
|
4372
|
+
const { timeoutMs, pollMs } = waitSettings(ctx);
|
|
4373
|
+
const deadline = Date.now() + timeoutMs;
|
|
4374
|
+
let current = task;
|
|
4375
|
+
while (!terminal.has(current.status)) {
|
|
4376
|
+
if (Date.now() >= deadline) return { task: current, timedOut: true };
|
|
4377
|
+
await new Promise((resolve4) => setTimeout(resolve4, pollMs));
|
|
4378
|
+
current = await requestResourcePackageApi(ctx, "GET", `/api/resource-packages/tasks/${encodeURIComponent(task.id)}`);
|
|
4379
|
+
}
|
|
4380
|
+
return { task: current, timedOut: false };
|
|
4381
|
+
}
|
|
4382
|
+
var taskIdFlag2 = { name: "task-id", type: "string", required: true, desc: "Resource package task ID" };
|
|
4383
|
+
var waitFlags = [
|
|
4384
|
+
{ name: "no-wait", type: "boolean", desc: "Return after submission without polling" },
|
|
4385
|
+
{ name: "wait-timeout-seconds", type: "number", desc: "Maximum poll duration in seconds (default: 1800)" },
|
|
4386
|
+
{ name: "poll-interval-ms", type: "number", desc: "Poll interval from 250 to 60000 milliseconds (default: 1500)" }
|
|
4387
|
+
];
|
|
4388
|
+
function listPath2(ctx) {
|
|
4389
|
+
const kind = ctx.str("kind");
|
|
4390
|
+
const selectedScope = ctx.str("scope");
|
|
4391
|
+
const status = ctx.str("status");
|
|
4392
|
+
if (kind && !["export", "import"].includes(kind)) throw new CliValidationError("--kind must be export or import");
|
|
4393
|
+
if (selectedScope && !["personal", "company"].includes(selectedScope)) throw new CliValidationError("--scope must be personal or company");
|
|
4394
|
+
if (status && !statuses.has(status)) throw new CliValidationError("--status is invalid");
|
|
4395
|
+
const page = ctx.optionalNum("page") ?? 1;
|
|
4396
|
+
const pageSize = ctx.optionalNum("pageSize") ?? 20;
|
|
4397
|
+
if (!Number.isSafeInteger(page) || page < 1) throw new CliValidationError("--page must be a positive integer");
|
|
4398
|
+
if (![20, 50, 100].includes(pageSize)) throw new CliValidationError("--page-size must be 20, 50, or 100");
|
|
4399
|
+
const query2 = new URLSearchParams();
|
|
4400
|
+
if (kind) query2.set("kind", kind);
|
|
4401
|
+
if (selectedScope) query2.set("scope", selectedScope);
|
|
4402
|
+
if (status) query2.set("status", status);
|
|
4403
|
+
query2.set("page", String(page));
|
|
4404
|
+
query2.set("pageSize", String(pageSize));
|
|
4405
|
+
return `/api/resource-packages/tasks?${query2}`;
|
|
4406
|
+
}
|
|
4407
|
+
var listResourcePackages = {
|
|
4408
|
+
service: "agent",
|
|
4409
|
+
resource: "resource-package",
|
|
4410
|
+
command: "list",
|
|
4411
|
+
description: "List personal and company resource package tasks",
|
|
4412
|
+
helpText: previewNote,
|
|
4413
|
+
flags: [
|
|
4414
|
+
{ name: "kind", type: "string", desc: "Filter by export or import" },
|
|
4415
|
+
{ name: "scope", type: "string", desc: "Filter by personal or company" },
|
|
4416
|
+
{ name: "status", type: "string", desc: "Filter by task status" },
|
|
4417
|
+
{ name: "page", type: "number", desc: "Page number (default: 1)" },
|
|
4418
|
+
{ name: "page-size", type: "number", desc: "Page size: 20, 50, or 100 (default: 20)" }
|
|
4419
|
+
],
|
|
4420
|
+
risk: "read",
|
|
4421
|
+
validate: (ctx) => {
|
|
4422
|
+
listPath2(ctx);
|
|
4423
|
+
},
|
|
4424
|
+
dryRun: (ctx) => ({ method: "GET", url: listPath2(ctx) }),
|
|
4425
|
+
execute: (ctx) => requestResourcePackageApi(ctx, "GET", listPath2(ctx))
|
|
4426
|
+
};
|
|
4427
|
+
var showResourcePackage = {
|
|
4428
|
+
service: "agent",
|
|
4429
|
+
resource: "resource-package",
|
|
4430
|
+
command: "show",
|
|
4431
|
+
description: "Show a resource package task and its item results",
|
|
4432
|
+
flags: [taskIdFlag2],
|
|
4433
|
+
risk: "read",
|
|
4434
|
+
validate: (ctx) => {
|
|
4435
|
+
taskPath(ctx);
|
|
4436
|
+
},
|
|
4437
|
+
dryRun: (ctx) => ({ method: "GET", url: taskPath(ctx) }),
|
|
4438
|
+
execute: (ctx) => requestResourcePackageApi(ctx, "GET", taskPath(ctx))
|
|
4439
|
+
};
|
|
4440
|
+
var previewResourcePackageExport = {
|
|
4441
|
+
service: "agent",
|
|
4442
|
+
resource: "resource-package",
|
|
4443
|
+
command: "export-preview",
|
|
4444
|
+
description: "Preview export resources and dependencies",
|
|
4445
|
+
helpText: previewNote,
|
|
4446
|
+
flags: [{ name: "roots", type: "string", required: true, desc: "JSON, @file, or stdin (-) array of resource references" }],
|
|
4447
|
+
risk: "read",
|
|
4448
|
+
validate: (ctx) => {
|
|
4449
|
+
references(ctx, "roots");
|
|
4450
|
+
},
|
|
4451
|
+
dryRun: (ctx) => ({ method: "POST", url: "/api/resource-packages/exports/preview", body: { roots: references(ctx, "roots") } }),
|
|
4452
|
+
execute: (ctx) => requestResourcePackageApi(ctx, "POST", "/api/resource-packages/exports/preview", { roots: references(ctx, "roots") })
|
|
4453
|
+
};
|
|
4454
|
+
function exportBody(ctx) {
|
|
4455
|
+
return {
|
|
4456
|
+
requestKey: ctx.str("requestKey") || randomUUID2(),
|
|
4457
|
+
kind: "export",
|
|
4458
|
+
scope: scope(ctx),
|
|
4459
|
+
payload: {
|
|
4460
|
+
roots: references(ctx, "roots"),
|
|
4461
|
+
excluded: references(ctx, "excluded"),
|
|
4462
|
+
...ctx.str("fileNameBase") ? { fileNameBase: ctx.str("fileNameBase") } : {}
|
|
4463
|
+
}
|
|
4464
|
+
};
|
|
4465
|
+
}
|
|
4466
|
+
function validateExport(ctx) {
|
|
4467
|
+
exportBody(ctx);
|
|
4468
|
+
if (ctx.str("requestKey")) id(ctx, "requestKey", "request-key");
|
|
4469
|
+
const base = ctx.str("fileNameBase");
|
|
4470
|
+
if (base && (base.length > 160 || !/^[^\\/\x00-\x1f]+$/.test(base))) {
|
|
4471
|
+
throw new CliValidationError("--file-name-base must be a safe filename base of at most 160 characters");
|
|
4472
|
+
}
|
|
4473
|
+
if (ctx.bool("noWait") && ctx.str("output")) throw new CliValidationError("--no-wait cannot be combined with --output");
|
|
4474
|
+
if (!ctx.bool("noWait")) waitSettings(ctx);
|
|
4475
|
+
}
|
|
4476
|
+
var exportResourcePackage = {
|
|
4477
|
+
service: "agent",
|
|
4478
|
+
resource: "resource-package",
|
|
4479
|
+
command: "export",
|
|
4480
|
+
description: "Export a personal or company resource package and download the artifact",
|
|
4481
|
+
helpText: previewNote,
|
|
4482
|
+
flags: [
|
|
4483
|
+
{ name: "scope", type: "string", required: true, desc: "Export scope: personal or company" },
|
|
4484
|
+
{ name: "roots", type: "string", required: true, desc: "JSON, @file, or stdin (-) array of root resources" },
|
|
4485
|
+
{ name: "excluded", type: "string", desc: "JSON or @file array of dependencies to exclude" },
|
|
4486
|
+
{ name: "file-name-base", type: "string", desc: "Optional output ZIP base name" },
|
|
4487
|
+
{ name: "request-key", type: "string", desc: "Optional idempotency key; reuse only for the same export" },
|
|
4488
|
+
{ name: "output", type: "string", desc: "Local ZIP path; defaults to the artifact filename" },
|
|
4489
|
+
{ name: "timezone", type: "string", desc: "IANA timezone for generated artifact filename (default: UTC)" },
|
|
4490
|
+
...waitFlags
|
|
4491
|
+
],
|
|
4492
|
+
risk: "write",
|
|
4493
|
+
validate: validateExport,
|
|
4494
|
+
preflight: validateExport,
|
|
4495
|
+
dryRun: (ctx) => ({ method: "POST", url: "/api/resource-packages/tasks", body: exportBody(ctx) }),
|
|
4496
|
+
execute: async (ctx) => {
|
|
4497
|
+
let task = await requestResourcePackageApi(ctx, "POST", "/api/resource-packages/tasks", exportBody(ctx));
|
|
4498
|
+
if (ctx.bool("noWait")) return { status: "submitted", task };
|
|
4499
|
+
const waited = await waitForTask(ctx, task);
|
|
4500
|
+
task = waited.task;
|
|
4501
|
+
if (waited.timedOut) return { status: "still_running", task };
|
|
4502
|
+
if (task.status !== "succeeded" || !task.artifactAvailable) return { status: "completed", task };
|
|
4503
|
+
const artifact = await downloadArtifact(ctx, task, ctx.str("output") || void 0, ctx.str("timezone") || void 0);
|
|
4504
|
+
return { status: "downloaded", task, artifact };
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
function validateImport(ctx) {
|
|
4508
|
+
if (!ctx.str("file")) throw new CliValidationError("--file is required");
|
|
4509
|
+
scope(ctx);
|
|
4510
|
+
stringArray(ctx, "confirmations", "confirmations");
|
|
4511
|
+
replacementMap(ctx);
|
|
4512
|
+
if (ctx.str("uploadId")) id(ctx, "uploadId", "upload-id");
|
|
4513
|
+
if (ctx.str("requestKey")) id(ctx, "requestKey", "request-key");
|
|
4514
|
+
if (!ctx.bool("noWait")) waitSettings(ctx);
|
|
4515
|
+
}
|
|
4516
|
+
function reviewPreflight(preflight, replacements, confirmations) {
|
|
4517
|
+
const unresolvedBlockers = preflight.blockers.filter((item) => {
|
|
4518
|
+
if (item.code !== "CORE_SYSTEM_AGENT_UNRESOLVED" || !item.referenceKey) return true;
|
|
4519
|
+
const replacement = replacements[item.referenceKey];
|
|
4520
|
+
return !replacement || replacement !== "__skip_resource__" && !item.replacementCandidates?.some((candidate) => candidate.id === replacement);
|
|
4521
|
+
});
|
|
4522
|
+
const missingConfirmations = preflight.confirmations.filter((item) => !confirmations.includes(item.code));
|
|
4523
|
+
return { unresolvedBlockers, missingConfirmations };
|
|
4524
|
+
}
|
|
4525
|
+
var importResourcePackage = {
|
|
4526
|
+
service: "agent",
|
|
4527
|
+
resource: "resource-package",
|
|
4528
|
+
command: "import",
|
|
4529
|
+
description: "Upload, preflight, confirm, and import a resource package with resume support",
|
|
4530
|
+
flags: [
|
|
4531
|
+
{ name: "file", type: "string", required: true, desc: "Path to a non-empty resource package ZIP" },
|
|
4532
|
+
{ name: "scope", type: "string", required: true, desc: "Import scope: personal or company" },
|
|
4533
|
+
{ name: "upload-id", type: "string", desc: "Explicit upload ID to resume" },
|
|
4534
|
+
{ name: "request-key", type: "string", desc: "Optional idempotency key; reuse only for the same import" },
|
|
4535
|
+
{ name: "confirmations", type: "string", desc: "JSON or @file array of required confirmation codes" },
|
|
4536
|
+
{ name: "system-replacements", type: "string", desc: "JSON or @file mapping of reference keys to target IDs or __skip_resource__" },
|
|
4537
|
+
{ name: "accept-warnings", type: "boolean", desc: "Accept all warnings from the current preflight snapshot" },
|
|
4538
|
+
{ name: "allow-duplicate", type: "boolean", desc: "Allow a package previously imported successfully" },
|
|
4539
|
+
...waitFlags
|
|
4540
|
+
],
|
|
4541
|
+
risk: "write",
|
|
4542
|
+
validate: validateImport,
|
|
4543
|
+
preflight: validateImport,
|
|
4544
|
+
dryRun: (ctx) => ({ method: "WORKFLOW", url: "/api/resource-packages/uploads", body: {
|
|
4545
|
+
file: ctx.str("file"),
|
|
4546
|
+
scope: scope(ctx),
|
|
4547
|
+
resume: true,
|
|
4548
|
+
wait: !ctx.bool("noWait")
|
|
4549
|
+
} }),
|
|
4550
|
+
execute: async (ctx) => {
|
|
4551
|
+
const { completed, statePath: statePath2, requestKey } = await uploadPackage(ctx, {
|
|
4552
|
+
filePath: ctx.str("file"),
|
|
4553
|
+
scope: scope(ctx),
|
|
4554
|
+
uploadId: ctx.str("uploadId") || void 0,
|
|
4555
|
+
requestKey: ctx.str("requestKey") || void 0
|
|
4556
|
+
});
|
|
4557
|
+
const confirmations = stringArray(ctx, "confirmations", "confirmations");
|
|
4558
|
+
const replacements = replacementMap(ctx);
|
|
4559
|
+
const review = reviewPreflight(completed.preflight, replacements, confirmations);
|
|
4560
|
+
if (completed.duplicateImport && !ctx.bool("allowDuplicate") || completed.preflight.warnings.length && !ctx.bool("acceptWarnings") || review.unresolvedBlockers.length || review.missingConfirmations.length) {
|
|
4561
|
+
return {
|
|
4562
|
+
status: "review_required",
|
|
4563
|
+
uploadId: completed.uploadId,
|
|
4564
|
+
requestKey,
|
|
4565
|
+
duplicateImport: completed.duplicateImport,
|
|
4566
|
+
preflight: completed.preflight,
|
|
4567
|
+
...review
|
|
4568
|
+
};
|
|
4569
|
+
}
|
|
4570
|
+
let task;
|
|
4571
|
+
try {
|
|
4572
|
+
task = await requestResourcePackageApi(
|
|
4573
|
+
ctx,
|
|
4574
|
+
"POST",
|
|
4575
|
+
`/api/resource-packages/uploads/${encodeURIComponent(completed.uploadId)}/confirm`,
|
|
4576
|
+
{
|
|
4577
|
+
requestKey,
|
|
4578
|
+
preflightSnapshotId: completed.preflight.snapshotId,
|
|
4579
|
+
confirmations,
|
|
4580
|
+
systemReplacements: replacements
|
|
4581
|
+
}
|
|
4582
|
+
);
|
|
4583
|
+
} catch (error) {
|
|
4584
|
+
const changed = resourcePackagePreflightChange(error);
|
|
4585
|
+
if (changed) return {
|
|
4586
|
+
status: "review_required",
|
|
4587
|
+
reason: "preflight_changed",
|
|
4588
|
+
uploadId: completed.uploadId,
|
|
4589
|
+
requestKey,
|
|
4590
|
+
preflight: changed
|
|
4591
|
+
};
|
|
4592
|
+
throw error;
|
|
4593
|
+
}
|
|
4594
|
+
await clearUploadState(statePath2);
|
|
4595
|
+
if (ctx.bool("noWait")) return { status: "submitted", task };
|
|
4596
|
+
const waited = await waitForTask(ctx, task);
|
|
4597
|
+
return { status: waited.timedOut ? "still_running" : "completed", task: waited.task };
|
|
4598
|
+
}
|
|
4599
|
+
};
|
|
4600
|
+
var downloadResourcePackageCommand = {
|
|
4601
|
+
service: "agent",
|
|
4602
|
+
resource: "resource-package",
|
|
4603
|
+
command: "download",
|
|
4604
|
+
description: "Download or resume a completed export artifact and verify its SHA-256",
|
|
4605
|
+
flags: [
|
|
4606
|
+
taskIdFlag2,
|
|
4607
|
+
{ name: "output", type: "string", desc: "Local ZIP path; defaults to the artifact filename" },
|
|
4608
|
+
{ name: "timezone", type: "string", desc: "IANA timezone for generated artifact filename (default: UTC)" }
|
|
4609
|
+
],
|
|
4610
|
+
risk: "read",
|
|
4611
|
+
validate: (ctx) => {
|
|
4612
|
+
taskPath(ctx);
|
|
4613
|
+
},
|
|
4614
|
+
dryRun: (ctx) => ({ method: "GET", url: `${taskPath(ctx)}/artifact` }),
|
|
4615
|
+
execute: async (ctx) => {
|
|
4616
|
+
const task = await requestResourcePackageApi(ctx, "GET", taskPath(ctx));
|
|
4617
|
+
if (task.kind !== "export" || task.status !== "succeeded" || !task.artifactAvailable) {
|
|
4618
|
+
throw new Error("This task does not have an available export artifact");
|
|
4619
|
+
}
|
|
4620
|
+
return downloadArtifact(ctx, task, ctx.str("output") || void 0, ctx.str("timezone") || void 0);
|
|
4621
|
+
}
|
|
4622
|
+
};
|
|
4623
|
+
var cancelResourcePackage = {
|
|
4624
|
+
service: "agent",
|
|
4625
|
+
resource: "resource-package",
|
|
4626
|
+
command: "cancel",
|
|
4627
|
+
description: "Request cancellation of a running resource package task",
|
|
4628
|
+
flags: [taskIdFlag2],
|
|
4629
|
+
risk: "high-risk-write",
|
|
4630
|
+
validate: (ctx) => {
|
|
4631
|
+
taskPath(ctx);
|
|
4632
|
+
},
|
|
4633
|
+
dryRun: (ctx) => ({ method: "POST", url: `${taskPath(ctx)}/cancel` }),
|
|
4634
|
+
execute: (ctx) => requestResourcePackageApi(ctx, "POST", `${taskPath(ctx)}/cancel`, {})
|
|
4635
|
+
};
|
|
4636
|
+
var retryResourcePackage = {
|
|
4637
|
+
service: "agent",
|
|
4638
|
+
resource: "resource-package",
|
|
4639
|
+
command: "retry",
|
|
4640
|
+
description: "Retry a retryable failed resource package task",
|
|
4641
|
+
flags: [taskIdFlag2, ...waitFlags],
|
|
4642
|
+
risk: "write",
|
|
4643
|
+
validate: (ctx) => {
|
|
4644
|
+
taskPath(ctx);
|
|
4645
|
+
if (!ctx.bool("noWait")) waitSettings(ctx);
|
|
4646
|
+
},
|
|
4647
|
+
dryRun: (ctx) => ({ method: "POST", url: `${taskPath(ctx)}/retry` }),
|
|
4648
|
+
execute: async (ctx) => {
|
|
4649
|
+
const task = await requestResourcePackageApi(ctx, "POST", `${taskPath(ctx)}/retry`, {});
|
|
4650
|
+
if (ctx.bool("noWait")) return { status: "submitted", task };
|
|
4651
|
+
const waited = await waitForTask(ctx, task);
|
|
4652
|
+
return { status: waited.timedOut ? "still_running" : "completed", task: waited.task };
|
|
4653
|
+
}
|
|
4654
|
+
};
|
|
4655
|
+
var resourcePackageCommands = [
|
|
4656
|
+
listResourcePackages,
|
|
4657
|
+
showResourcePackage,
|
|
4658
|
+
previewResourcePackageExport,
|
|
4659
|
+
exportResourcePackage,
|
|
4660
|
+
importResourcePackage,
|
|
4661
|
+
downloadResourcePackageCommand,
|
|
4662
|
+
cancelResourcePackage,
|
|
4663
|
+
retryResourcePackage
|
|
4664
|
+
];
|
|
4665
|
+
|
|
4016
4666
|
// src/commands/te-agent/index.ts
|
|
4017
4667
|
var commands = [
|
|
4018
4668
|
...notificationCommands,
|
|
@@ -4113,15 +4763,24 @@ var commands = [
|
|
|
4113
4763
|
findArchivedConversations,
|
|
4114
4764
|
restoreConversation,
|
|
4115
4765
|
// Sandbox tools (local scan of /home/ta/.local/bin managed shims)
|
|
4116
|
-
listSandboxTools
|
|
4766
|
+
listSandboxTools,
|
|
4767
|
+
...resourcePackageCommands
|
|
4117
4768
|
];
|
|
4118
4769
|
var te_agent_default = commands;
|
|
4119
4770
|
export {
|
|
4771
|
+
cancelResourcePackage,
|
|
4120
4772
|
te_agent_default as default,
|
|
4773
|
+
downloadResourcePackageCommand,
|
|
4774
|
+
exportResourcePackage,
|
|
4775
|
+
importResourcePackage,
|
|
4776
|
+
listResourcePackages,
|
|
4121
4777
|
notificationGet,
|
|
4122
4778
|
notificationList,
|
|
4123
4779
|
notificationMarkRead,
|
|
4124
4780
|
notificationRecipients,
|
|
4125
4781
|
notificationSend,
|
|
4126
|
-
notificationUnreadCount
|
|
4782
|
+
notificationUnreadCount,
|
|
4783
|
+
previewResourcePackageExport,
|
|
4784
|
+
retryResourcePackage,
|
|
4785
|
+
showResourcePackage
|
|
4127
4786
|
};
|