@talesofai/neta-skills 0.16.2 → 0.16.6
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/CHANGELOG.md +27 -0
- package/bin/apis/recsys.js +9 -0
- package/bin/commands/adventure_campaign/create_adventure_campaign.cmd.js +1 -4
- package/bin/commands/adventure_campaign/list_my_adventure_campaigns.cmd.js +0 -3
- package/bin/commands/adventure_campaign/update_adventure_campaign.cmd.js +1 -4
- package/bin/commands/character_elementum/list_my_characters.cmd.js +0 -4
- package/bin/commands/character_elementum/list_my_elementum.cmd.js +0 -4
- package/bin/commands/community/create_comment.cmd.js +2 -1
- package/bin/commands/community/favor_collection.cmd.js +2 -1
- package/bin/commands/community/get_hashtag_collections.cmd.en_us.yml +0 -3
- package/bin/commands/community/get_hashtag_collections.cmd.js +2 -4
- package/bin/commands/community/get_hashtag_collections.cmd.zh_cn.yml +0 -2
- package/bin/commands/community/like_collection.cmd.js +2 -1
- package/bin/commands/community/read_collection.cmd.js +3 -2
- package/bin/commands/community/subscribe_user.cmd.js +2 -1
- package/bin/commands/creative/edit_colleciton.cmd.js +7 -5
- package/bin/commands/creative/publish_collection.cmd.js +6 -4
- package/bin/commands/creative/remove_background.cmd.js +3 -2
- package/bin/commands/creative/request_character_or_elementum.cmd.en_us.yml +0 -6
- package/bin/commands/creative/request_character_or_elementum.cmd.js +6 -12
- package/bin/commands/creative/request_character_or_elementum.cmd.zh_cn.yml +0 -6
- package/bin/commands/creative/upload.cmd.en_us.yml +0 -4
- package/bin/commands/creative/upload.cmd.js +9 -15
- package/bin/commands/creative/upload.cmd.zh_cn.yml +0 -4
- package/bin/commands/load.js +15 -8
- package/bin/commands/premium/create_premium_order.cmd.js +2 -1
- package/bin/commands/premium/get_current_premium_plan.cmd.js +2 -4
- package/bin/commands/premium/get_premium_order.cmd.js +2 -1
- package/bin/commands/premium/list_premium_orders.cmd.js +2 -1
- package/bin/commands/premium/list_premium_plans.cmd.js +4 -3
- package/bin/commands/premium/pay_premium_order.cmd.js +4 -3
- package/bin/commands/user/login.cmd.en_us.yml +1 -4
- package/bin/commands/user/login.cmd.js +2 -4
- package/bin/commands/user/login.cmd.zh_cn.yml +1 -4
- package/bin/utils/auth.js +3 -3
- package/bin/utils/env.js +1 -1
- package/bin/utils/errors.en_us.yml +25 -0
- package/bin/utils/errors.js +29 -0
- package/bin/utils/errors.zh_cn.yml +25 -0
- package/package.json +1 -1
- package/skills/neta/SKILL.md +0 -17
- package/skills/neta-adventure/SKILL.md +0 -17
- package/skills/neta-character/SKILL.md +0 -17
- package/skills/neta-community/SKILL.md +0 -17
- package/skills/neta-creative/SKILL.md +0 -17
- package/skills/neta-elementum/SKILL.md +0 -17
- package/skills/neta-space/SKILL.md +0 -17
- package/skills/neta-suggest/SKILL.md +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @neta/skills-neta
|
|
2
2
|
|
|
3
|
+
## 0.16.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- update read_collection commands api
|
|
8
|
+
- add user check for all commands exclude "login"
|
|
9
|
+
- move inline error text to utils/errors.ts file
|
|
10
|
+
- remove authorization from SKILL.md, add login usage to not authorization error and login -h command
|
|
11
|
+
|
|
12
|
+
## 0.16.5
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- update auth api base url
|
|
17
|
+
|
|
18
|
+
## 0.16.4
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- fix build
|
|
23
|
+
|
|
24
|
+
## 0.16.3
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- update auth api resource
|
|
29
|
+
|
|
3
30
|
## 0.16.2
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/bin/apis/recsys.js
CHANGED
|
@@ -19,11 +19,20 @@ export const createRecsysApis = (client) => {
|
|
|
19
19
|
const response = await client.post("/v1/recsys/validate-tax-path", params);
|
|
20
20
|
return response.data;
|
|
21
21
|
};
|
|
22
|
+
const detail = async (uuid) => {
|
|
23
|
+
const response = await client.get("/v1/recsys/interactive/details", {
|
|
24
|
+
params: {
|
|
25
|
+
uuid,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
return response.data.module_list[0];
|
|
29
|
+
};
|
|
22
30
|
return {
|
|
23
31
|
suggestKeywords,
|
|
24
32
|
suggestTags,
|
|
25
33
|
suggestCategories,
|
|
26
34
|
suggestContent,
|
|
27
35
|
validateTaxPath,
|
|
36
|
+
detail,
|
|
28
37
|
};
|
|
29
38
|
};
|
|
@@ -39,10 +39,7 @@ export const createAdventureCampaign = createCommand({
|
|
|
39
39
|
title: meta.title,
|
|
40
40
|
description: meta.description,
|
|
41
41
|
inputSchema: createAdventureCampaignParameters,
|
|
42
|
-
}, async ({ name, mission_plot, subtitle, status, header_img, background_img, mission_task, mission_plot_attention, }, {
|
|
43
|
-
if (!user) {
|
|
44
|
-
throw new Error("Not authenticated. Please check your NETA_TOKEN or login.");
|
|
45
|
-
}
|
|
42
|
+
}, async ({ name, mission_plot, subtitle, status, header_img, background_img, mission_task, mission_plot_attention, }, { apis }) => {
|
|
46
43
|
const result = await apis.travelCampaign.createCampaign({
|
|
47
44
|
name,
|
|
48
45
|
mission_plot,
|
|
@@ -29,9 +29,6 @@ export const listMyAdventureCampaigns = createCommand({
|
|
|
29
29
|
description: meta.description,
|
|
30
30
|
inputSchema: listMyAdventureCampaignsParameters,
|
|
31
31
|
}, async ({ page_index, page_size }, { user, apis }) => {
|
|
32
|
-
if (!user) {
|
|
33
|
-
throw new Error("Not authenticated. Please check your NETA_TOKEN or login.");
|
|
34
|
-
}
|
|
35
32
|
const result = await apis.travelCampaign.listMyCampaigns({
|
|
36
33
|
user_uuid: user.uuid,
|
|
37
34
|
page_index,
|
|
@@ -40,10 +40,7 @@ export const updateAdventureCampaign = createCommand({
|
|
|
40
40
|
title: meta.title,
|
|
41
41
|
description: meta.description,
|
|
42
42
|
inputSchema: updateAdventureCampaignParameters,
|
|
43
|
-
}, async ({ campaign_uuid, name, mission_plot, subtitle, status, header_img, background_img, mission_task, mission_plot_attention, }, {
|
|
44
|
-
if (!user) {
|
|
45
|
-
throw new Error("Not authenticated. Please check your NETA_TOKEN or login.");
|
|
46
|
-
}
|
|
43
|
+
}, async ({ campaign_uuid, name, mission_plot, subtitle, status, header_img, background_img, mission_task, mission_plot_attention, }, { apis }) => {
|
|
47
44
|
const patch = Object.fromEntries(Object.entries({
|
|
48
45
|
name,
|
|
49
46
|
mission_plot,
|
|
@@ -17,10 +17,6 @@ export const listMyCharacters = createCommand({
|
|
|
17
17
|
description: meta.description,
|
|
18
18
|
inputSchema: listMyCharactersParameters,
|
|
19
19
|
}, async ({ keyword, page_index, page_size }, { apis, user }) => {
|
|
20
|
-
// Get current user info to obtain UUID
|
|
21
|
-
if (!user) {
|
|
22
|
-
throw new Error("Failed to get user info. Please check your NETA_TOKEN.");
|
|
23
|
-
}
|
|
24
20
|
const result = await apis.tcp.listMyTCPs({
|
|
25
21
|
user_uuid: user.uuid,
|
|
26
22
|
parent_type: "oc",
|
|
@@ -17,10 +17,6 @@ export const listMyElementum = createCommand({
|
|
|
17
17
|
description: meta.description,
|
|
18
18
|
inputSchema: listMyElementumParameters,
|
|
19
19
|
}, async ({ keyword, page_index, page_size }, { apis, user }) => {
|
|
20
|
-
// Get current user info to obtain UUID
|
|
21
|
-
if (!user) {
|
|
22
|
-
throw new Error("Failed to get user info. Please check your NETA_TOKEN.");
|
|
23
|
-
}
|
|
24
20
|
const result = await apis.tcp.listMyTCPs({
|
|
25
21
|
user_uuid: user.uuid,
|
|
26
22
|
parent_type: "elementum",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -30,7 +31,7 @@ export const createCommentCmd = createCommand({
|
|
|
30
31
|
at_users: atUsersArray,
|
|
31
32
|
});
|
|
32
33
|
if (!result.success) {
|
|
33
|
-
throw new Error(
|
|
34
|
+
throw new Error(errors.create_comment_fail);
|
|
34
35
|
}
|
|
35
36
|
return {
|
|
36
37
|
success: true,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -20,7 +21,7 @@ export const favorCollectionCmd = createCommand({
|
|
|
20
21
|
const action = is_cancel ? "cancel_favor" : "favor";
|
|
21
22
|
const result = await apis.collection.favorCollection(uuid, { is_cancel });
|
|
22
23
|
if (!result.success) {
|
|
23
|
-
throw new Error(
|
|
24
|
+
throw new Error(errors.action_fail.replace("{action}", action));
|
|
24
25
|
}
|
|
25
26
|
return {
|
|
26
27
|
success: true,
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
5
6
|
name: Type.String(),
|
|
6
7
|
title: Type.String(),
|
|
7
8
|
description: Type.String(),
|
|
8
|
-
errors: Type.Object({
|
|
9
|
-
no_activity_space: Type.String(),
|
|
10
|
-
}),
|
|
11
9
|
}), import.meta);
|
|
12
10
|
const fetchSelectedCollectionsByHashtagV1Parameters = Type.Object({
|
|
13
11
|
hashtag: Type.String(),
|
|
@@ -28,7 +26,7 @@ export const getHashtagCollections = createCommand({
|
|
|
28
26
|
const activityDetail = hashtagResult?.activity_detail;
|
|
29
27
|
const activity_uuid = activityDetail?.uuid;
|
|
30
28
|
if (!activity_uuid) {
|
|
31
|
-
throw new Error(
|
|
29
|
+
throw new Error(errors.hashtag_not_linked_to_activity_space.replace("{hashtag}", String(hashtag ?? "").trim()));
|
|
32
30
|
}
|
|
33
31
|
const result = await apis.activity.fetchSelectedCollections(activity_uuid, {
|
|
34
32
|
page_index,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -20,7 +21,7 @@ export const likeCollectionCmd = createCommand({
|
|
|
20
21
|
const action = is_cancel ? "unliked" : "liked";
|
|
21
22
|
const success = await apis.collection.likeCollection(uuid, { is_cancel });
|
|
22
23
|
if (!success) {
|
|
23
|
-
throw new Error(
|
|
24
|
+
throw new Error(errors.action_fail.replace("{action}", action));
|
|
24
25
|
}
|
|
25
26
|
return {
|
|
26
27
|
success: true,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { isVerseCTA } from "../../apis/collection.js";
|
|
3
|
+
import { errors } from "../../utils/errors.js";
|
|
3
4
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
4
5
|
import { createCommand } from "../factory.js";
|
|
5
6
|
const mete = parseMeta(Type.Object({
|
|
@@ -15,9 +16,9 @@ export const readCollectionCmd = createCommand({
|
|
|
15
16
|
uuid: Type.String(),
|
|
16
17
|
}),
|
|
17
18
|
}, async ({ uuid }, { apis }) => {
|
|
18
|
-
const res = await apis.
|
|
19
|
+
const res = await apis.recsys.detail(uuid);
|
|
19
20
|
if (!res || res.template_id !== "NORMAL") {
|
|
20
|
-
throw new Error(
|
|
21
|
+
throw new Error(errors.collection_not_found.replace("{uuid}", uuid));
|
|
21
22
|
}
|
|
22
23
|
const name = res.json_data.name;
|
|
23
24
|
const description = res.json_data.description ?? "";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -23,7 +24,7 @@ export const subscribeUserCmd = createCommand({
|
|
|
23
24
|
is_cancel,
|
|
24
25
|
});
|
|
25
26
|
if (!result.success) {
|
|
26
|
-
throw new Error(
|
|
27
|
+
throw new Error(errors.action_fail.replace("{action}", action));
|
|
27
28
|
}
|
|
28
29
|
return {
|
|
29
30
|
success: true,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -32,7 +33,7 @@ export const editCollection = createCommand({
|
|
|
32
33
|
}, async ({ uuid, name, description, status, hashtags, artifacts, remix_instruct }, { apis }) => {
|
|
33
34
|
const [collection] = await apis.collection.collectionDetails([uuid]);
|
|
34
35
|
if (!collection) {
|
|
35
|
-
throw new Error(
|
|
36
|
+
throw new Error(errors.creative_collection_not_found.replace("{uuid}", uuid));
|
|
36
37
|
}
|
|
37
38
|
const payload = {
|
|
38
39
|
uuid,
|
|
@@ -70,16 +71,17 @@ export const editCollection = createCommand({
|
|
|
70
71
|
payload.activity = activity?.activity_detail?.uuid ?? null;
|
|
71
72
|
}
|
|
72
73
|
if (artifacts) {
|
|
73
|
-
const
|
|
74
|
+
const artifactIds = artifacts.split(",");
|
|
75
|
+
const artifactDetails = await apis.artifact.artifactDetail(artifactIds);
|
|
74
76
|
if (artifactDetails.length < 1 || artifactDetails.length > 12) {
|
|
75
|
-
throw new Error(
|
|
77
|
+
throw new Error(errors.collection_artifact_count_range);
|
|
76
78
|
}
|
|
77
79
|
artifactDetails.forEach((artifact, index) => {
|
|
78
80
|
if (!artifact) {
|
|
79
|
-
throw new Error(
|
|
81
|
+
throw new Error(errors.collection_artifact_not_found.replace("{artifact_uuid}", artifactIds[index] ?? ""));
|
|
80
82
|
}
|
|
81
83
|
if (artifact.status !== "SUCCESS") {
|
|
82
|
-
throw new Error(
|
|
84
|
+
throw new Error(errors.collection_artifact_not_success.replace("{artifact_uuid}", artifactIds[index] ?? ""));
|
|
83
85
|
}
|
|
84
86
|
});
|
|
85
87
|
const coverArtifact = artifactDetails.find((artifact) => artifact.url) ?? null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
@@ -31,16 +32,17 @@ export const publishCollection = createCommand({
|
|
|
31
32
|
const tags = await Promise.all(hashtags?.split(",")?.map((tag) => apis.hashtag.createHashtag(tag)) ?? []);
|
|
32
33
|
const tagDetails = await Promise.all(tags.map((tag) => apis.hashtag.fetchHashtag(tag.name)));
|
|
33
34
|
const activity = tagDetails.find((tag) => tag?.activity_detail?.uuid) ?? null;
|
|
34
|
-
const
|
|
35
|
+
const artifactIds = artifacts.split(",");
|
|
36
|
+
const artifactDetails = await apis.artifact.artifactDetail(artifactIds);
|
|
35
37
|
if (artifactDetails.length < 1 || artifactDetails.length > 12) {
|
|
36
|
-
throw new Error(
|
|
38
|
+
throw new Error(errors.collection_artifact_count_range);
|
|
37
39
|
}
|
|
38
40
|
artifactDetails.forEach((artifact, index) => {
|
|
39
41
|
if (!artifact) {
|
|
40
|
-
throw new Error(
|
|
42
|
+
throw new Error(errors.collection_artifact_not_found.replace("{artifact_uuid}", artifactIds[index] ?? ""));
|
|
41
43
|
}
|
|
42
44
|
if (artifact.status !== "SUCCESS") {
|
|
43
|
-
throw new Error(
|
|
45
|
+
throw new Error(errors.collection_artifact_not_success.replace("{artifact_uuid}", artifactIds[index] ?? ""));
|
|
44
46
|
}
|
|
45
47
|
});
|
|
46
48
|
const uuid = await apis.collection.createCollection();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { polling } from "../../utils/polling.js";
|
|
4
5
|
import { createCommand } from "../factory.js";
|
|
@@ -34,7 +35,7 @@ export const removeBackground = createCommand({
|
|
|
34
35
|
!artifacts[0] ||
|
|
35
36
|
artifacts[0].modality !== "PICTURE" ||
|
|
36
37
|
artifacts[0].status !== "SUCCESS") {
|
|
37
|
-
throw new Error(
|
|
38
|
+
throw new Error(errors.invalid_picture_artifact_uuid);
|
|
38
39
|
}
|
|
39
40
|
return apis.artifact.postProcess(input_image, "0_null/抠图SEG", {
|
|
40
41
|
entrance: "PICTURE,CLI",
|
|
@@ -69,7 +70,7 @@ export const removeBackgroundNoCrop = createCommand({
|
|
|
69
70
|
!artifacts[0] ||
|
|
70
71
|
artifacts[0].modality !== "PICTURE" ||
|
|
71
72
|
artifacts[0].status !== "SUCCESS") {
|
|
72
|
-
throw new Error(
|
|
73
|
+
throw new Error(errors.invalid_picture_artifact_uuid);
|
|
73
74
|
}
|
|
74
75
|
return apis.artifact.postProcess(input_image, "0_null/抠图SEG", {
|
|
75
76
|
entrance: "PICTURE,CLI",
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
name: request_character_or_elementum
|
|
2
2
|
title: Get Character or Elementum
|
|
3
3
|
description: Fetch detailed information about a character or elementum by exact name or UUID.
|
|
4
|
-
errors:
|
|
5
|
-
missing_id: Either name or uuid must be provided.
|
|
6
|
-
not_found: Character or elementum not found {identifier}
|
|
7
|
-
type_mismatch_character: The resolved type is "character", but parent_type="elementum" was specified. Please adjust parent_type or use a different name to search.
|
|
8
|
-
type_mismatch_elementum: The resolved type is "elementum", but parent_type="character" was specified. Please adjust parent_type or use a different name to search.
|
|
9
|
-
unknown_type: Unknown TCP type {type}
|
|
10
4
|
parameters:
|
|
11
5
|
name: |
|
|
12
6
|
Exact name of the character or elementum.
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { errors } from "../../utils/errors.js";
|
|
2
3
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
3
4
|
import { createCommand } from "../factory.js";
|
|
4
5
|
const meta = parseMeta(Type.Object({
|
|
5
6
|
name: Type.String(),
|
|
6
7
|
title: Type.String(),
|
|
7
8
|
description: Type.String(),
|
|
8
|
-
errors: Type.Object({
|
|
9
|
-
missing_id: Type.String(),
|
|
10
|
-
not_found: Type.String(),
|
|
11
|
-
type_mismatch_character: Type.String(),
|
|
12
|
-
type_mismatch_elementum: Type.String(),
|
|
13
|
-
unknown_type: Type.String(),
|
|
14
|
-
}),
|
|
15
9
|
parameters: Type.Object({
|
|
16
10
|
name: Type.String(),
|
|
17
11
|
uuid: Type.String(),
|
|
@@ -36,7 +30,7 @@ export const requestCharacterOrElementum = createCommand({
|
|
|
36
30
|
const targetType = parent_type === "both" ? ["character", "elementum"] : [parent_type];
|
|
37
31
|
const getTcp = async () => {
|
|
38
32
|
if (!uuid && !name) {
|
|
39
|
-
throw new Error(
|
|
33
|
+
throw new Error(errors.tcp_missing_id_or_name);
|
|
40
34
|
}
|
|
41
35
|
if (uuid) {
|
|
42
36
|
return await apis.tcp.tcpProfile(uuid);
|
|
@@ -66,11 +60,11 @@ export const requestCharacterOrElementum = createCommand({
|
|
|
66
60
|
};
|
|
67
61
|
const tcp = await getTcp();
|
|
68
62
|
if (!tcp) {
|
|
69
|
-
throw new Error(
|
|
63
|
+
throw new Error(errors.tcp_not_found.replace("{identifier}", String((name || uuid) ?? "").trim()));
|
|
70
64
|
}
|
|
71
65
|
if (tcp.type === "oc" || tcp.type === "official") {
|
|
72
66
|
if (!targetType.includes("character")) {
|
|
73
|
-
throw new Error(
|
|
67
|
+
throw new Error(errors.tcp_type_mismatch_character);
|
|
74
68
|
}
|
|
75
69
|
const assignValue = {
|
|
76
70
|
type: "character",
|
|
@@ -90,7 +84,7 @@ export const requestCharacterOrElementum = createCommand({
|
|
|
90
84
|
}
|
|
91
85
|
if (tcp.type === "elementum") {
|
|
92
86
|
if (!targetType.includes("elementum")) {
|
|
93
|
-
throw new Error(
|
|
87
|
+
throw new Error(errors.tcp_type_mismatch_elementum);
|
|
94
88
|
}
|
|
95
89
|
const assignValue = {
|
|
96
90
|
type: "elementum",
|
|
@@ -104,5 +98,5 @@ export const requestCharacterOrElementum = createCommand({
|
|
|
104
98
|
};
|
|
105
99
|
}
|
|
106
100
|
log.warn(`request_character_or_elementum: unknown tcp type: ${tcp.type}`);
|
|
107
|
-
throw new Error(
|
|
101
|
+
throw new Error(errors.tcp_unknown_type.replace("{type}", String(tcp.type)));
|
|
108
102
|
});
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
name: request_character_or_elementum
|
|
2
2
|
title: 请求角色或元素
|
|
3
3
|
description: 通过名称(精确匹配)或UUID获取角色或元素的详细信息
|
|
4
|
-
errors:
|
|
5
|
-
missing_id: 必须提供 name 或 uuid 参数之一
|
|
6
|
-
not_found: 未找到角色或元素 {identifier}
|
|
7
|
-
type_mismatch_character: 找到的类型为 "character"(角色),但指定了 parent_type="elementum"(风格元素)。请调整 parent_type 参数或使用不同的名称搜索。
|
|
8
|
-
type_mismatch_elementum: 找到的类型为 "elementum"(风格元素),但指定了 parent_type="character"(角色)。请调整 parent_type 参数或使用不同的名称搜索。
|
|
9
|
-
unknown_type: 未知 TCP 类型 {type}
|
|
10
4
|
parameters:
|
|
11
5
|
name: |
|
|
12
6
|
角色或元素的名称(精确匹配)
|
|
@@ -4,7 +4,3 @@ description: Upload a media file (image or video) to create a media artifact.
|
|
|
4
4
|
|
|
5
5
|
parameters:
|
|
6
6
|
file_path: Local media path (absolute or relative to cwd), or http(s) URL to fetch the file
|
|
7
|
-
|
|
8
|
-
errors:
|
|
9
|
-
file_type_not_supported: Media file type not supported
|
|
10
|
-
file_size_too_large: Media file size too large, maximum size is {max_size} bytes
|
|
@@ -3,6 +3,7 @@ import { CompleteMultipartUploadCommand, CreateMultipartUploadCommand, S3Client,
|
|
|
3
3
|
import { Type } from "@sinclair/typebox";
|
|
4
4
|
import { filetypeinfo } from "magic-bytes.js";
|
|
5
5
|
import plimit from "p-limit";
|
|
6
|
+
import { errors } from "../../utils/errors.js";
|
|
6
7
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
7
8
|
import { polling } from "../../utils/polling.js";
|
|
8
9
|
import { createCommand } from "../factory.js";
|
|
@@ -39,10 +40,6 @@ const meta = parseMeta(Type.Object({
|
|
|
39
40
|
parameters: Type.Object({
|
|
40
41
|
file_path: Type.String(),
|
|
41
42
|
}),
|
|
42
|
-
errors: Type.Object({
|
|
43
|
-
file_type_not_supported: Type.String(),
|
|
44
|
-
file_size_too_large: Type.String(),
|
|
45
|
-
}),
|
|
46
43
|
}), import.meta);
|
|
47
44
|
const s3Upload = async (data, options) => {
|
|
48
45
|
const { mimeType, regionOptions, credentials, logger } = options;
|
|
@@ -51,7 +48,7 @@ const s3Upload = async (data, options) => {
|
|
|
51
48
|
const now = Date.now();
|
|
52
49
|
const expires = new Date(expiration).getTime();
|
|
53
50
|
if (now > expires) {
|
|
54
|
-
throw new Error(
|
|
51
|
+
throw new Error(errors.sts_token_expired);
|
|
55
52
|
}
|
|
56
53
|
const client = new S3Client({
|
|
57
54
|
region,
|
|
@@ -124,12 +121,12 @@ const createArtifact = async (url, options) => {
|
|
|
124
121
|
const res = await polling(() => apis.artifact.artifactDetail([uuid]), (result) => {
|
|
125
122
|
const artifact = result[0];
|
|
126
123
|
if (!artifact)
|
|
127
|
-
throw new Error(
|
|
124
|
+
throw new Error(errors.artifact_not_found);
|
|
128
125
|
logger.debug("polling: %o", artifact);
|
|
129
126
|
return artifact.status !== "PENDING" && artifact.status !== "MODERATION";
|
|
130
127
|
}, 1000, 60 * 1000);
|
|
131
128
|
if (res.isTimeout) {
|
|
132
|
-
throw new Error(
|
|
129
|
+
throw new Error(errors.operation_timeout);
|
|
133
130
|
}
|
|
134
131
|
// biome-ignore lint/style/noNonNullAssertion: checked
|
|
135
132
|
return res.result[0];
|
|
@@ -144,10 +141,7 @@ export const upload = createCommand({
|
|
|
144
141
|
inputSchema: Type.Object({
|
|
145
142
|
file_path: Type.String({ description: meta.parameters.file_path }),
|
|
146
143
|
}),
|
|
147
|
-
}, async ({ file_path }, { apis,
|
|
148
|
-
if (!user) {
|
|
149
|
-
throw new Error("Not authenticated. Please check your NETA_TOKEN or login.");
|
|
150
|
-
}
|
|
144
|
+
}, async ({ file_path }, { apis, log }) => {
|
|
151
145
|
const regionOptions = apis.baseUrl.endsWith(".cn")
|
|
152
146
|
? OSS_STS_OPTIONS_CN
|
|
153
147
|
: OSS_STS_OPTIONS_US;
|
|
@@ -159,11 +153,11 @@ export const upload = createCommand({
|
|
|
159
153
|
const infos = filetypeinfo(file);
|
|
160
154
|
const info = infos[0]; // always use first extension
|
|
161
155
|
if (!info || !info.extension || !info.mime) {
|
|
162
|
-
throw new Error(
|
|
156
|
+
throw new Error(errors.upload_file_type_not_supported);
|
|
163
157
|
}
|
|
164
158
|
if (SUPPORTED_IMAGE_TYPES.includes(info.extension)) {
|
|
165
159
|
if (file.length > DEFAULT_IMAGE_LIMIT_SIZE) {
|
|
166
|
-
throw new Error(
|
|
160
|
+
throw new Error(errors.upload_file_size_too_large.replace("{max_size}", DEFAULT_IMAGE_LIMIT_SIZE.toString()));
|
|
167
161
|
}
|
|
168
162
|
const credentials = await apis.oss.getStsCredentials(info.extension);
|
|
169
163
|
const url = await s3Upload(file, {
|
|
@@ -180,7 +174,7 @@ export const upload = createCommand({
|
|
|
180
174
|
}
|
|
181
175
|
if (SUPPORTED_VIDEO_TYPES.includes(info.extension)) {
|
|
182
176
|
if (file.length > DEFAULT_VIDEO_LIMIT_SIZE) {
|
|
183
|
-
throw new Error(
|
|
177
|
+
throw new Error(errors.upload_file_size_too_large.replace("{max_size}", DEFAULT_VIDEO_LIMIT_SIZE.toString()));
|
|
184
178
|
}
|
|
185
179
|
const credentials = await apis.oss.getVideoStsCredentials(info.extension);
|
|
186
180
|
const url = await s3Upload(file, {
|
|
@@ -195,5 +189,5 @@ export const upload = createCommand({
|
|
|
195
189
|
logger: log,
|
|
196
190
|
});
|
|
197
191
|
}
|
|
198
|
-
throw new Error(
|
|
192
|
+
throw new Error(errors.upload_file_type_not_supported);
|
|
199
193
|
});
|
package/bin/commands/load.js
CHANGED
|
@@ -14,7 +14,7 @@ import { Type } from "@sinclair/typebox";
|
|
|
14
14
|
import { AssertError, Value } from "@sinclair/typebox/value";
|
|
15
15
|
import { createApis } from "../apis/index.js";
|
|
16
16
|
import { API_BASE_URL, IS_DEV } from "../utils/env.js";
|
|
17
|
-
import { ApiResponseError } from "../utils/errors.js";
|
|
17
|
+
import { ApiResponseError, errors } from "../utils/errors.js";
|
|
18
18
|
import { getSysLocale } from "../utils/lang.js";
|
|
19
19
|
import { logger } from "../utils/logger.js";
|
|
20
20
|
import { setLocale } from "../utils/parse_meta.js";
|
|
@@ -52,7 +52,8 @@ export const buildCommands = async (cli) => {
|
|
|
52
52
|
]);
|
|
53
53
|
commands.forEach((cmd) => {
|
|
54
54
|
const command = cli.command(cmd.name);
|
|
55
|
-
command.description(cmd.
|
|
55
|
+
command.description(cmd.description || "");
|
|
56
|
+
command.summary(cmd.title || "");
|
|
56
57
|
const inputSchema = cmd.inputSchema;
|
|
57
58
|
if (inputSchema && "properties" in inputSchema) {
|
|
58
59
|
const properties = inputSchema.properties;
|
|
@@ -99,17 +100,22 @@ export const buildCommands = async (cli) => {
|
|
|
99
100
|
"x-platform": "nieta-app/web",
|
|
100
101
|
},
|
|
101
102
|
});
|
|
102
|
-
const user = cmd.name === "login"
|
|
103
|
+
const user = cmd.name === "login"
|
|
103
104
|
? null
|
|
104
105
|
: await apis.user.me().catch((e) => {
|
|
105
106
|
if (e instanceof ApiResponseError) {
|
|
106
|
-
|
|
107
|
+
logger.info(`${e.name}[${e.code}]: ${e.message}`);
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
else {
|
|
110
|
+
logger.warn(e);
|
|
111
|
+
}
|
|
112
|
+
throw new Error(errors.need_login);
|
|
109
113
|
});
|
|
110
114
|
const startTime = Date.now();
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
if (user) {
|
|
116
|
+
logger.debug("[telemetry] user: %s", user.uuid);
|
|
117
|
+
trackConfigUser({ user_unique_id: user.uuid });
|
|
118
|
+
}
|
|
113
119
|
track("command_call", {
|
|
114
120
|
command: cmd.name,
|
|
115
121
|
...formatCommandParams(args),
|
|
@@ -120,7 +126,8 @@ export const buildCommands = async (cli) => {
|
|
|
120
126
|
await cmd
|
|
121
127
|
.execute(input, {
|
|
122
128
|
apis,
|
|
123
|
-
user
|
|
129
|
+
// biome-ignore lint/style/noNonNullAssertion: ignore type error when user is null by login command
|
|
130
|
+
user: user,
|
|
124
131
|
log: logger,
|
|
125
132
|
})
|
|
126
133
|
.then((result) => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { parseDate } from "../../utils/date.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
const meta = parseMeta(Type.Object({
|
|
@@ -20,7 +21,7 @@ export const createPremiumOrder = createCommand({
|
|
|
20
21
|
}),
|
|
21
22
|
}, async ({ spu_uuid }, { apis }) => {
|
|
22
23
|
if (!IS_GLOBAL) {
|
|
23
|
-
throw new Error(
|
|
24
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
24
25
|
}
|
|
25
26
|
const order = await apis.commerce.createOrder({
|
|
26
27
|
spu_uuid,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { parseDate } from "../../utils/date.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
const PlanningMap = {
|
|
@@ -20,10 +21,7 @@ export const getCurrentPremiumPlan = createCommand({
|
|
|
20
21
|
description: meta.description,
|
|
21
22
|
}, async (_, { user }) => {
|
|
22
23
|
if (!IS_GLOBAL) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
}
|
|
25
|
-
if (!user) {
|
|
26
|
-
throw new Error("Not authenticated. Please check your NETA_TOKEN or login.");
|
|
24
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
27
25
|
}
|
|
28
26
|
const level = user.properties?.vip_level ?? 0;
|
|
29
27
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { parseDate } from "../../utils/date.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
const meta = parseMeta(Type.Object({
|
|
@@ -20,7 +21,7 @@ export const getPremiumOrder = createCommand({
|
|
|
20
21
|
}),
|
|
21
22
|
}, async ({ order_uuid }, { apis }) => {
|
|
22
23
|
if (!IS_GLOBAL) {
|
|
23
|
-
throw new Error(
|
|
24
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
24
25
|
}
|
|
25
26
|
const order = await apis.commerce.order({ order_uuid });
|
|
26
27
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { parseDate } from "../../utils/date.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
const meta = parseMeta(Type.Object({
|
|
@@ -31,7 +32,7 @@ export const listPremiumOrders = createCommand({
|
|
|
31
32
|
}),
|
|
32
33
|
}, async ({ page_index, page_size }, { apis }) => {
|
|
33
34
|
if (!IS_GLOBAL) {
|
|
34
|
-
throw new Error(
|
|
35
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
35
36
|
}
|
|
36
37
|
const { list, total } = await apis.commerce.orders({
|
|
37
38
|
page_index,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { Value } from "@sinclair/typebox/value";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { safeParseJson } from "../../utils/json.js";
|
|
5
6
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
6
7
|
import { createCommand } from "../factory.js";
|
|
@@ -46,11 +47,11 @@ export const listPremiumPlans = createCommand({
|
|
|
46
47
|
description: meta.description,
|
|
47
48
|
}, async (_, { apis }) => {
|
|
48
49
|
if (!IS_GLOBAL) {
|
|
49
|
-
throw new Error(
|
|
50
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
50
51
|
}
|
|
51
52
|
const plansConfigValue = await apis.commerce.listPlansConfig();
|
|
52
53
|
if (!plansConfigValue || plansConfigValue.type !== "json") {
|
|
53
|
-
throw new Error(
|
|
54
|
+
throw new Error(errors.premium_plans_config_not_found);
|
|
54
55
|
}
|
|
55
56
|
const json = safeParseJson(plansConfigValue.value);
|
|
56
57
|
try {
|
|
@@ -61,7 +62,7 @@ export const listPremiumPlans = createCommand({
|
|
|
61
62
|
};
|
|
62
63
|
}
|
|
63
64
|
catch (error) {
|
|
64
|
-
throw new Error(
|
|
65
|
+
throw new Error(errors.premium_plans_config_invalid, {
|
|
65
66
|
cause: error,
|
|
66
67
|
});
|
|
67
68
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { parseDate } from "../../utils/date.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
const meta = parseMeta(Type.Object({
|
|
@@ -24,14 +25,14 @@ export const payPremiumOrder = createCommand({
|
|
|
24
25
|
}),
|
|
25
26
|
}, async ({ order_uuid, channel }, { apis }) => {
|
|
26
27
|
if (!IS_GLOBAL) {
|
|
27
|
-
throw new Error(
|
|
28
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
28
29
|
}
|
|
29
30
|
const order = await apis.commerce.order({ order_uuid });
|
|
30
31
|
if (order.status !== "UNPAID") {
|
|
31
|
-
throw new Error(
|
|
32
|
+
throw new Error(errors.order_not_unpaid);
|
|
32
33
|
}
|
|
33
34
|
if (parseDate(order.valid_until).isBefore(Date.now())) {
|
|
34
|
-
throw new Error(
|
|
35
|
+
throw new Error(errors.order_expired);
|
|
35
36
|
}
|
|
36
37
|
const result = await apis.commerce.pay({
|
|
37
38
|
order_uuid,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
name: login
|
|
2
2
|
title: Login
|
|
3
|
-
description: Login to your Neta account
|
|
3
|
+
description: Login to your Neta account by OAuth2 device code flow. 1. Run command "login --action request-code" to request a device code. 2. Open the browser and visit the URL provided by the command to verify. 3. Run command "login --action verify-code" to verify the device code and complete the login.
|
|
4
4
|
parameters:
|
|
5
5
|
action: Action to perform (request-code or verify-code)
|
|
6
|
-
|
|
7
|
-
errors:
|
|
8
|
-
not_supported_in_current_region: This command is not supported in the current region, please set NETA_TOKEN environment variable for authentication.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { requestDeviceCode, verifyDeviceCode } from "../../utils/auth.js";
|
|
3
3
|
import { IS_GLOBAL } from "../../utils/env.js";
|
|
4
|
+
import { errors } from "../../utils/errors.js";
|
|
4
5
|
import { parseMeta } from "../../utils/parse_meta.js";
|
|
5
6
|
import { createCommand } from "../factory.js";
|
|
6
7
|
export const meta = parseMeta(Type.Object({
|
|
@@ -10,9 +11,6 @@ export const meta = parseMeta(Type.Object({
|
|
|
10
11
|
parameters: Type.Object({
|
|
11
12
|
action: Type.String(),
|
|
12
13
|
}),
|
|
13
|
-
errors: Type.Object({
|
|
14
|
-
not_supported_in_current_region: Type.String(),
|
|
15
|
-
}),
|
|
16
14
|
}), import.meta);
|
|
17
15
|
export const login = createCommand({
|
|
18
16
|
name: meta.name,
|
|
@@ -26,7 +24,7 @@ export const login = createCommand({
|
|
|
26
24
|
}),
|
|
27
25
|
}, async ({ action }, { apis }) => {
|
|
28
26
|
if (!IS_GLOBAL) {
|
|
29
|
-
throw new Error(
|
|
27
|
+
throw new Error(errors.not_supported_in_current_region);
|
|
30
28
|
}
|
|
31
29
|
if (action === "verify-code") {
|
|
32
30
|
await verifyDeviceCode();
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
name: login
|
|
2
2
|
title: 登录
|
|
3
|
-
description:
|
|
3
|
+
description: 通过 OAuth2 设备授权码流登录到你的 Neta 账户。 1. 运行命令 "login --action request-code" 请求验证码。 2. 打开浏览器并访问命令提供的 URL 完成校验。 3. 运行命令 "login --action verify-code" 验证验证码并完成登录流程。
|
|
4
4
|
parameters:
|
|
5
5
|
action: 要执行的操作 (request-code 请求验证码, verify-code 验证验证码)
|
|
6
|
-
|
|
7
|
-
errors:
|
|
8
|
-
not_supported_in_current_region: 当前区域不支持此命令, 请设置 NETA_TOKEN 环境变量进行身份验证
|
package/bin/utils/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { Value } from "@sinclair/typebox/value";
|
|
3
3
|
import { deleteConfig, readConfig, writeConfig } from "./config.js";
|
|
4
|
-
import {
|
|
4
|
+
import { AUTH_API_BASE_URL, CLIENT_ID } from "./env.js";
|
|
5
5
|
import { ApiResponseError } from "./errors.js";
|
|
6
6
|
import { safeParseJson } from "./json.js";
|
|
7
7
|
import { logger } from "./logger.js";
|
|
@@ -121,7 +121,7 @@ export const requestDeviceCode = async () => {
|
|
|
121
121
|
body: new URLSearchParams({
|
|
122
122
|
client_id: CLIENT_ID,
|
|
123
123
|
scope: "profile email offline_access",
|
|
124
|
-
resource:
|
|
124
|
+
resource: "https://api.talesofai",
|
|
125
125
|
}),
|
|
126
126
|
});
|
|
127
127
|
if (!res.ok) {
|
|
@@ -168,7 +168,7 @@ export const refreshToken = async () => {
|
|
|
168
168
|
grant_type: "refresh_token",
|
|
169
169
|
refresh_token: tokenConfig.refresh_token,
|
|
170
170
|
scope: "profile email offline_access",
|
|
171
|
-
resource:
|
|
171
|
+
resource: "https://api.talesofai",
|
|
172
172
|
}),
|
|
173
173
|
});
|
|
174
174
|
if (!res.ok) {
|
package/bin/utils/env.js
CHANGED
|
@@ -5,7 +5,7 @@ dotenv.config({
|
|
|
5
5
|
});
|
|
6
6
|
export const IS_DEV = process.env["NODE_ENV"] === "development";
|
|
7
7
|
export const API_BASE_URL = process.env["NETA_API_BASE_URL"] ?? "https://api.talesofai.com";
|
|
8
|
-
export const AUTH_API_BASE_URL = process.env["NETA_AUTH_API_BASE_URL"] ?? "https://auth.
|
|
8
|
+
export const AUTH_API_BASE_URL = process.env["NETA_AUTH_API_BASE_URL"] ?? "https://auth.neta.art";
|
|
9
9
|
export const CLIENT_ID = process.env["NETA_CLIENT_ID"] ?? "ft6zb5zp7fqmq8y807okv";
|
|
10
10
|
export const NETA_TOKEN = process.env["NETA_TOKEN"] ?? "";
|
|
11
11
|
export const IS_GLOBAL = API_BASE_URL.endsWith("talesofai.com");
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
need_login: Need to login to the NETA account, run command "login --help" for more information or set NETA_TOKEN environment variable for authentication.
|
|
2
|
+
not_supported_in_current_region: This command is not supported in the current region, please set NETA_TOKEN environment variable for authentication.
|
|
3
|
+
premium_plans_config_not_found: Premium subscription plans config not found
|
|
4
|
+
premium_plans_config_invalid: Premium subscription plans config is invalid
|
|
5
|
+
order_not_unpaid: Order is not unpaid
|
|
6
|
+
order_expired: Order is expired
|
|
7
|
+
sts_token_expired: STS token expired
|
|
8
|
+
artifact_not_found: Artifact not found
|
|
9
|
+
operation_timeout: Timeout
|
|
10
|
+
upload_file_type_not_supported: Media file type not supported
|
|
11
|
+
upload_file_size_too_large: Media file size too large, maximum size is {max_size} bytes
|
|
12
|
+
invalid_picture_artifact_uuid: Input is not a valid picture artifact UUID
|
|
13
|
+
tcp_missing_id_or_name: Either name or uuid must be provided.
|
|
14
|
+
tcp_not_found: Character or elementum not found {identifier}
|
|
15
|
+
tcp_type_mismatch_character: The resolved type is "character", but parent_type="elementum" was specified. Please adjust parent_type or use a different name to search.
|
|
16
|
+
tcp_type_mismatch_elementum: The resolved type is "elementum", but parent_type="character" was specified. Please adjust parent_type or use a different name to search.
|
|
17
|
+
tcp_unknown_type: Unknown TCP type {type}
|
|
18
|
+
hashtag_not_linked_to_activity_space: Hashtag "{hashtag}" is not linked to any activity space.
|
|
19
|
+
collection_artifact_count_range: artifacts must be between 1 and 12
|
|
20
|
+
collection_artifact_not_found: artifact {artifact_uuid} not found
|
|
21
|
+
collection_artifact_not_success: artifact {artifact_uuid} status is not success
|
|
22
|
+
creative_collection_not_found: collection {uuid} not found
|
|
23
|
+
action_fail: "{action} fail"
|
|
24
|
+
create_comment_fail: create_comment fail
|
|
25
|
+
collection_not_found: Collection "{uuid}" not found
|
package/bin/utils/errors.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
1
2
|
import { AxiosError } from "axios";
|
|
2
3
|
import { safeParseJson } from "./json.js";
|
|
4
|
+
import { parseMeta } from "./parse_meta.js";
|
|
3
5
|
export class ApiResponseError extends Error {
|
|
4
6
|
code;
|
|
5
7
|
message;
|
|
@@ -62,3 +64,30 @@ export const handleAxiosError = (error) => {
|
|
|
62
64
|
cause: error,
|
|
63
65
|
});
|
|
64
66
|
};
|
|
67
|
+
export const errors = parseMeta(Type.Object({
|
|
68
|
+
need_login: Type.String(),
|
|
69
|
+
not_supported_in_current_region: Type.String(),
|
|
70
|
+
premium_plans_config_not_found: Type.String(),
|
|
71
|
+
premium_plans_config_invalid: Type.String(),
|
|
72
|
+
order_not_unpaid: Type.String(),
|
|
73
|
+
order_expired: Type.String(),
|
|
74
|
+
sts_token_expired: Type.String(),
|
|
75
|
+
artifact_not_found: Type.String(),
|
|
76
|
+
operation_timeout: Type.String(),
|
|
77
|
+
upload_file_type_not_supported: Type.String(),
|
|
78
|
+
upload_file_size_too_large: Type.String(),
|
|
79
|
+
invalid_picture_artifact_uuid: Type.String(),
|
|
80
|
+
tcp_missing_id_or_name: Type.String(),
|
|
81
|
+
tcp_not_found: Type.String(),
|
|
82
|
+
tcp_type_mismatch_character: Type.String(),
|
|
83
|
+
tcp_type_mismatch_elementum: Type.String(),
|
|
84
|
+
tcp_unknown_type: Type.String(),
|
|
85
|
+
hashtag_not_linked_to_activity_space: Type.String(),
|
|
86
|
+
collection_artifact_count_range: Type.String(),
|
|
87
|
+
collection_artifact_not_found: Type.String(),
|
|
88
|
+
collection_artifact_not_success: Type.String(),
|
|
89
|
+
creative_collection_not_found: Type.String(),
|
|
90
|
+
action_fail: Type.String(),
|
|
91
|
+
create_comment_fail: Type.String(),
|
|
92
|
+
collection_not_found: Type.String(),
|
|
93
|
+
}), import.meta);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
need_login: 需要登录到 NETA 账户, 请运行 "login --help" 获取更多信息或设置 NETA_TOKEN 环境变量进行身份验证
|
|
2
|
+
not_supported_in_current_region: 当前区域不支持此命令, 请设置 NETA_TOKEN 环境变量进行身份验证
|
|
3
|
+
premium_plans_config_not_found: 未找到会员订阅方案配置
|
|
4
|
+
premium_plans_config_invalid: 会员订阅方案配置无效
|
|
5
|
+
order_not_unpaid: 订单不是未支付状态
|
|
6
|
+
order_expired: 订单已过期
|
|
7
|
+
sts_token_expired: STS 凭证已过期
|
|
8
|
+
artifact_not_found: 未找到素材
|
|
9
|
+
operation_timeout: 操作超时
|
|
10
|
+
upload_file_type_not_supported: 文件类型不支持
|
|
11
|
+
upload_file_size_too_large: 文件大小超过最大限制, 最大支持 {max_size} 字节
|
|
12
|
+
invalid_picture_artifact_uuid: 输入不是有效的图片素材 UUID
|
|
13
|
+
tcp_missing_id_or_name: 必须提供 name 或 uuid 参数之一
|
|
14
|
+
tcp_not_found: 未找到角色或元素 {identifier}
|
|
15
|
+
tcp_type_mismatch_character: 找到的类型为 "character"(角色),但指定了 parent_type="elementum"(风格元素)。请调整 parent_type 参数或使用不同的名称搜索。
|
|
16
|
+
tcp_type_mismatch_elementum: 找到的类型为 "elementum"(风格元素),但指定了 parent_type="character"(角色)。请调整 parent_type 参数或使用不同的名称搜索。
|
|
17
|
+
tcp_unknown_type: 未知 TCP 类型 {type}
|
|
18
|
+
hashtag_not_linked_to_activity_space: Hashtag "{hashtag}" 未关联任何活动空间
|
|
19
|
+
collection_artifact_count_range: 素材数量必须在 1 到 12 之间
|
|
20
|
+
collection_artifact_not_found: 未找到素材 {artifact_uuid}
|
|
21
|
+
collection_artifact_not_success: 素材 {artifact_uuid} 状态不是成功
|
|
22
|
+
creative_collection_not_found: 未找到合集 {uuid}
|
|
23
|
+
action_fail: "{action} 失败"
|
|
24
|
+
create_comment_fail: 发表评论失败
|
|
25
|
+
collection_not_found: 未找到合集 "{uuid}"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@talesofai/neta-skills",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.6",
|
|
4
4
|
"description": "Neta API pi coding agent skills for interacting with Neta API to generate images, videos, songs, and manage characters/elements.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/skills/neta/SKILL.md
CHANGED
|
@@ -49,23 +49,6 @@ npx skills add talesofai/neta-skills/skills/neta-adventure
|
|
|
49
49
|
- Creating or managing visual style elements (scenes, props, clothing, poses, atmospheres, memes) → use `neta-elementum`
|
|
50
50
|
3. Use this skill only when boundaries are unclear or when you need to explain which sub-skill to pick.
|
|
51
51
|
|
|
52
|
-
## Authorization
|
|
53
|
-
|
|
54
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
55
|
-
|
|
56
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
57
|
-
```bash
|
|
58
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
59
|
-
```
|
|
60
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
61
|
-
|
|
62
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
63
|
-
|
|
64
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
65
|
-
```bash
|
|
66
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
67
|
-
```
|
|
68
|
-
|
|
69
52
|
**Region / fallback**: Device login is only supported when the CLI is using the **global** API host (see `NETA_API_BASE_URL` / `talesofai.com`). If the command errors with “not supported in the current region”, tell the user to authenticate via the **`NETA_TOKEN`** environment variable instead.
|
|
70
53
|
|
|
71
54
|
## Capability map and sub-skill overview
|
|
@@ -20,23 +20,6 @@ Determine mode before acting. Do not ask multiple questions.
|
|
|
20
20
|
|
|
21
21
|
Once mode is established, do not re-ask.
|
|
22
22
|
|
|
23
|
-
## Authorization
|
|
24
|
-
|
|
25
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
26
|
-
|
|
27
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
28
|
-
```bash
|
|
29
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
30
|
-
```
|
|
31
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
32
|
-
|
|
33
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
34
|
-
|
|
35
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
36
|
-
```bash
|
|
37
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
38
|
-
```
|
|
39
|
-
|
|
40
23
|
## Commands
|
|
41
24
|
|
|
42
25
|
**Create a campaign**
|
|
@@ -9,23 +9,6 @@ Guide users from inspiration to forging, completing the creation and management
|
|
|
9
9
|
|
|
10
10
|
> This skill requires the **neta-creative** skill to use `make_image` for visual previews.
|
|
11
11
|
|
|
12
|
-
## Authorization
|
|
13
|
-
|
|
14
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
15
|
-
|
|
16
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
17
|
-
```bash
|
|
18
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
19
|
-
```
|
|
20
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
21
|
-
|
|
22
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
23
|
-
|
|
24
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
25
|
-
```bash
|
|
26
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
27
|
-
```
|
|
28
|
-
|
|
29
12
|
## Command Usage
|
|
30
13
|
|
|
31
14
|
### Create Character
|
|
@@ -17,23 +17,6 @@ Used to interact with the Neta API for community feed browsing, interactions, an
|
|
|
17
17
|
3. If the user needs **systematic research or complex filtering by categories/keywords**, switch to `neta-suggest`.
|
|
18
18
|
4. If the user wants to **create new content** (images/videos/songs/MVs), switch to `neta-creative`.
|
|
19
19
|
|
|
20
|
-
## Authorization
|
|
21
|
-
|
|
22
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
23
|
-
|
|
24
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
25
|
-
```bash
|
|
26
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
27
|
-
```
|
|
28
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
29
|
-
|
|
30
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
31
|
-
|
|
32
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
33
|
-
```bash
|
|
34
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
35
|
-
```
|
|
36
|
-
|
|
37
20
|
## Commands
|
|
38
21
|
|
|
39
22
|
### Collection
|
|
@@ -15,23 +15,6 @@ Used to interact with the Neta API for multimedia content creation, creation‑r
|
|
|
15
15
|
2. If, during creation, you discover that the real need is more like “browse recommendations / casually explore / research topics”, combine this skill with `neta-community` or `neta-suggest` instead of overloading this skill.
|
|
16
16
|
3. **Premium** (plans, orders, Stripe): use the commands below. Run **`get_current_premium_plan`** before and after checkout so the user can confirm tier (and end time if returned). Commerce needs the **global** Neta API—see the premium reference. If creation is blocked by **quota / credits (电量)** or **usage frequency (频率)**, say why in one beat; if an upgrade fits their goal, offer the path once (list plans → create order → pay)—**do not** repeat upgrade nudges in the same conversation unless the user asks.
|
|
17
17
|
|
|
18
|
-
## Authorization
|
|
19
|
-
|
|
20
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
21
|
-
|
|
22
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
23
|
-
```bash
|
|
24
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
25
|
-
```
|
|
26
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
27
|
-
|
|
28
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
29
|
-
|
|
30
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
31
|
-
```bash
|
|
32
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
33
|
-
```
|
|
34
|
-
|
|
35
18
|
## Commands
|
|
36
19
|
|
|
37
20
|
### Content creation
|
|
@@ -9,23 +9,6 @@ Through the "Elementum Alchemy" workflow, forge any visual concept into a reusab
|
|
|
9
9
|
|
|
10
10
|
> This skill requires the **neta-creative** skill to use `make_image` for visual previews.
|
|
11
11
|
|
|
12
|
-
## Authorization
|
|
13
|
-
|
|
14
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
15
|
-
|
|
16
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
17
|
-
```bash
|
|
18
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
19
|
-
```
|
|
20
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
21
|
-
|
|
22
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
23
|
-
|
|
24
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
25
|
-
```bash
|
|
26
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
27
|
-
```
|
|
28
|
-
|
|
29
12
|
## Command Usage
|
|
30
13
|
|
|
31
14
|
### Create Elementum
|
|
@@ -17,23 +17,6 @@ Used to interact with the Neta API to browse space‑level content.
|
|
|
17
17
|
- If needed, fetch characters and playable content inside the space.
|
|
18
18
|
3. If the user says “now generate an image/video/song for this space”, first collect the relevant space/collection info here, then switch to `neta-creative` for creation.
|
|
19
19
|
|
|
20
|
-
## Authorization
|
|
21
|
-
|
|
22
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
23
|
-
|
|
24
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
25
|
-
```bash
|
|
26
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
27
|
-
```
|
|
28
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
29
|
-
|
|
30
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
31
|
-
|
|
32
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
33
|
-
```bash
|
|
34
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
35
|
-
```
|
|
36
|
-
|
|
37
20
|
## Space concepts
|
|
38
21
|
|
|
39
22
|
> A space is a themed collection of gameplay experiences — a scene where content is produced and consumed.
|
|
@@ -12,23 +12,6 @@ description: Neta API research and recommendation skill — provide keyword/tag/
|
|
|
12
12
|
3. Before content creation, use this skill to research topics/tags/categories, then hand off to `neta-creative` for concrete creation.
|
|
13
13
|
4. When the user wants to like/comment or otherwise interact with specific works, switch to `neta-community`.
|
|
14
14
|
|
|
15
|
-
## Authorization
|
|
16
|
-
|
|
17
|
-
Use this when the user needs a **logged-in Neta identity** for CLI-backed flows and no valid session exists (or you would otherwise rely on `NETA_TOKEN`).
|
|
18
|
-
|
|
19
|
-
1. **Start the flow**: run **`neta login`** (default action is `request-code`).
|
|
20
|
-
```bash
|
|
21
|
-
npx -y @talesofai/neta-skills@latest login --action request-code
|
|
22
|
-
```
|
|
23
|
-
This begins the OAuth **device authorization** flow stored by the CLI.
|
|
24
|
-
|
|
25
|
-
2. **Browser step**: When the command returns device-authorization fields, show the user **`verification_uri_complete`** (the ready-to-open URL), tell them to open it in a browser and finish sign-in/consent there, then **return to the chat and explicitly say the browser step is done** so you know when to continue.
|
|
26
|
-
|
|
27
|
-
3. **Complete login**: After they confirm in chat, run **`neta login --action verify-code`** to exchange the device code for tokens. On success, show the returned **account basics**: **`uuid`** (long user id), **`nick_name`**, and **`avatar_url`**.
|
|
28
|
-
```bash
|
|
29
|
-
npx -y @talesofai/neta-skills@latest login --action verify-code
|
|
30
|
-
```
|
|
31
|
-
|
|
32
15
|
## Core capabilities
|
|
33
16
|
|
|
34
17
|
### 1. suggest_keywords — keyword suggestions
|