@talesofai/neta-skills 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +18 -10
  3. package/README.zh_cn.md +6 -6
  4. package/bin/apis/commerce.js +41 -0
  5. package/bin/apis/index.js +4 -0
  6. package/bin/commands/adventure_campaign/request_adventure_campaign.cmd.en_us.yml +1 -1
  7. package/bin/commands/load.js +15 -3
  8. package/bin/commands/premium/create_premium_order.cmd.en_us.yml +5 -0
  9. package/bin/commands/premium/create_premium_order.cmd.js +46 -0
  10. package/bin/commands/premium/create_premium_order.cmd.zh_cn.yml +5 -0
  11. package/bin/commands/premium/get_current_premium_plan.cmd.en_us.yml +3 -0
  12. package/bin/commands/premium/get_current_premium_plan.cmd.js +32 -0
  13. package/bin/commands/premium/get_current_premium_plan.cmd.zh_cn.yml +3 -0
  14. package/bin/commands/premium/get_premium_order.cmd.en_us.yml +5 -0
  15. package/bin/commands/premium/get_premium_order.cmd.js +44 -0
  16. package/bin/commands/premium/get_premium_order.cmd.zh_cn.yml +5 -0
  17. package/bin/commands/premium/list_premium_orders.cmd.en_us.yml +6 -0
  18. package/bin/commands/premium/list_premium_orders.cmd.js +59 -0
  19. package/bin/commands/premium/list_premium_orders.cmd.zh_cn.yml +6 -0
  20. package/bin/commands/premium/list_premium_plans.cmd.en_us.yml +3 -0
  21. package/bin/commands/premium/list_premium_plans.cmd.js +67 -0
  22. package/bin/commands/premium/list_premium_plans.cmd.zh_cn.yml +3 -0
  23. package/bin/commands/premium/pay_premium_order.cmd.en_us.yml +6 -0
  24. package/bin/commands/premium/pay_premium_order.cmd.js +44 -0
  25. package/bin/commands/premium/pay_premium_order.cmd.zh_cn.yml +6 -0
  26. package/bin/utils/date.js +66 -0
  27. package/bin/utils/parse_meta.js +1 -1
  28. package/package.json +2 -1
  29. package/skills/neta-adventure/SKILL.md +5 -5
  30. package/skills/neta-character/SKILL.md +8 -8
  31. package/skills/neta-character/references/character-creation.md +6 -6
  32. package/skills/neta-character/references/character-update.md +7 -7
  33. package/skills/neta-community/SKILL.md +8 -8
  34. package/skills/neta-community/references/character-search.md +20 -20
  35. package/skills/neta-community/references/hashtag-research.md +25 -25
  36. package/skills/neta-community/references/interactive-feed.md +27 -27
  37. package/skills/neta-community/references/social-interactive.md +10 -10
  38. package/skills/neta-creative/SKILL.md +53 -9
  39. package/skills/neta-creative/references/character-search.md +20 -20
  40. package/skills/neta-creative/references/collection-remix.md +1 -1
  41. package/skills/neta-creative/references/image-generation.md +14 -14
  42. package/skills/neta-creative/references/premium.md +68 -0
  43. package/skills/neta-creative/references/song-creation.md +4 -4
  44. package/skills/neta-creative/references/song-mv.md +15 -15
  45. package/skills/neta-creative/references/video-generation.md +5 -5
  46. package/skills/neta-elementum/SKILL.md +7 -7
  47. package/skills/neta-elementum/references/elementum-alchemy.md +8 -8
  48. package/skills/neta-elementum/references/elementum-update.md +8 -8
  49. package/skills/neta-space/SKILL.md +6 -6
  50. package/skills/neta-suggest/SKILL.md +34 -34
  51. package/skills/zh_cn/neta-adventure/SKILL.md +5 -5
  52. package/skills/zh_cn/neta-character/SKILL.md +8 -8
  53. package/skills/zh_cn/neta-character/references/character-creation.md +6 -6
  54. package/skills/zh_cn/neta-character/references/character-update.md +7 -7
  55. package/skills/zh_cn/neta-community/SKILL.md +9 -9
  56. package/skills/zh_cn/neta-community/references/character-search.md +20 -20
  57. package/skills/zh_cn/neta-community/references/hashtag-research.md +25 -25
  58. package/skills/zh_cn/neta-community/references/interactive-feed.md +30 -30
  59. package/skills/zh_cn/neta-community/references/social-interactive.md +10 -10
  60. package/skills/zh_cn/neta-creative/SKILL.md +8 -8
  61. package/skills/zh_cn/neta-creative/references/character-search.md +20 -20
  62. package/skills/zh_cn/neta-creative/references/collection-remix.md +1 -1
  63. package/skills/zh_cn/neta-creative/references/image-generation.md +14 -14
  64. package/skills/zh_cn/neta-creative/references/song-creation.md +4 -4
  65. package/skills/zh_cn/neta-creative/references/song-mv.md +15 -15
  66. package/skills/zh_cn/neta-creative/references/video-generation.md +5 -5
  67. package/skills/zh_cn/neta-elementum/SKILL.md +7 -7
  68. package/skills/zh_cn/neta-elementum/references/elementum-alchemy.md +8 -8
  69. package/skills/zh_cn/neta-elementum/references/elementum-update.md +8 -8
  70. package/skills/zh_cn/neta-space/SKILL.md +6 -6
  71. package/skills/zh_cn/neta-suggest/SKILL.md +55 -55
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @neta/skills-neta
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 54180c1: feat(premium): implement premium subscription commands and integrate dayjs for date handling
8
+
9
+ - Add premium subscription CLI commands: `create_premium_order`, `pay_premium_order`, `get_current_premium_plan`, `get_premium_order`, `list_premium_orders`, `list_premium_plans`; wire commerce APIs and command loading.
10
+ - Add `dayjs` and `src/utils/date.ts` for date formatting/parsing; adjust `parse_meta` as needed.
11
+ - Update `README.md` and `skills/neta-creative/SKILL.md`; add `skills/neta-creative/references/premium.md` for premium workflows.
12
+
3
13
  ## 0.13.0
4
14
 
5
15
  ### Minor Changes
package/README.md CHANGED
@@ -19,6 +19,7 @@ You can get your access token / NETA TOKEN from the [Neta Open Portal](https://w
19
19
  ## ✨ Features
20
20
 
21
21
  - 🎨 **Multimedia Creation:** Generate stunning images, videos, and songs using state-of-the-art AI models.
22
+ - ⭐ **Premium & Subscriptions:** List plans, create orders, start Stripe checkout, and verify the active tier via dedicated CLI commands (global API environment).
22
23
  - 🔧 **Image & Video Processing:** Effortlessly remove backgrounds and merge video assets.
23
24
  - 👤 **Character & Style Management:** Search, fetch details, and manage characters and stylistic elements.
24
25
  - 🏷️ **Community Integrations:** Explore trending hashtags, popular characters, and curated collections.
@@ -46,7 +47,7 @@ You can also install the specialized skills separately if your agent prefers mor
46
47
  # Community exploration (hashtags, spaces, interactive feed)
47
48
  npx skills add talesofai/neta-skills/skills/neta-community
48
49
 
49
- # Creation workflows (image / video / song)
50
+ # Creation workflows (image / video / song) and premium subscription flows
50
51
  npx skills add talesofai/neta-skills/skills/neta-creative
51
52
 
52
53
  # Discovery & suggestions (keywords, tags, categories, content)
@@ -67,7 +68,7 @@ npx skills add talesofai/neta-skills/skills/neta-adventure
67
68
 
68
69
  ### Available Commands
69
70
 
70
- The skill includes **34 commands** for various tasks:
71
+ The skill includes **42 commands** for various tasks:
71
72
 
72
73
  | Category | Command | Description |
73
74
  |----------|---------|-------------|
@@ -82,6 +83,12 @@ The skill includes **34 commands** for various tasks:
82
83
  | | `edit_collection` | Edit an existing collection (name, description, tags, status, etc.) |
83
84
  | | `publish_collection` | Publish or update a collection |
84
85
  | | `search_character_or_elementum` | Search reusable TCP building blocks (characters / elements / flows) |
86
+ | **Premium** | `get_current_premium_plan` | Get the signed-in user’s current tier and subscription end when applicable |
87
+ | | `list_premium_plans` | List available premium plans and SPU UUIDs |
88
+ | | `create_premium_order` | Create an order for a plan (by SPU UUID) |
89
+ | | `get_premium_order` | Fetch details for a single premium order |
90
+ | | `list_premium_orders` | List premium orders (paginated) |
91
+ | | `pay_premium_order` | Start payment for an unpaid order (e.g. Stripe Checkout) |
85
92
  | **VToken Management** | `create_character` | Create a character VToken (consumes credits) |
86
93
  | | `update_character` | Update an existing character VToken |
87
94
  | | `list_my_characters` | List all characters created by the current user |
@@ -136,14 +143,14 @@ export NETA_TOKEN=your_token_here
136
143
 
137
144
  ```bash
138
145
  # Get general help or specific command help
139
- npx -y @talesofai/neta-skills --help
140
- npx -y @talesofai/neta-skills make_image --help
146
+ npx -y @talesofai/neta-skills@latest --help
147
+ npx -y @talesofai/neta-skills@latest make_image --help
141
148
 
142
149
  # Example: Generate an image
143
- npx -y @talesofai/neta-skills make_image --prompt "A cyberpunk cityscape at night" --aspect "16:9"
150
+ npx -y @talesofai/neta-skills@latest make_image --prompt "A cyberpunk cityscape at night" --aspect "16:9"
144
151
 
145
152
  # Example: Search for characters or elementum
146
- npx -y @talesofai/neta-skills search_character_or_elementum --keywords "fantasy"
153
+ npx -y @talesofai/neta-skills@latest search_character_or_elementum --keywords "fantasy"
147
154
  ```
148
155
 
149
156
  ---
@@ -172,8 +179,8 @@ neta-skills/
172
179
  │ ├── neta-elementum/
173
180
  │ └── neta-adventure/
174
181
  ├── src/ # TypeScript source for the CLI
175
- │ ├── apis/ # Typed Neta API client helpers
176
- │ ├── commands/ # CLI command definitions (TS + YAML meta)
182
+ │ ├── apis/ # Typed Neta API client helpers (incl. commerce)
183
+ │ ├── commands/ # CLI command groups: creative, community, adventure, VToken, premium, …
177
184
  │ ├── utils/ # Shared utilities
178
185
  │ └── cli.ts # CLI entrypoint (TypeScript)
179
186
  ├── bin/ # Built JavaScript output for the CLI
@@ -203,6 +210,7 @@ Agents use these references to learn the optimal sequence of actions, parameter
203
210
  - **Song & MV Creation:** Workflows for composing songs and creating music videos with synchronized visuals.
204
211
  - **Character & Hashtag Research:** Processes for finding trending content, searching characters, and utilizing community trends.
205
212
  - **Character & Elementum Creation:** Character creation and elementum alchemy workflows.
213
+ - **Premium / Subscriptions:** Plan listing, order lifecycle, checkout channels, and environment limits. See `skills/neta-creative/references/premium.md`.
206
214
  - **Adventure Campaign Crafting & Play:** Multi-turn story creation workflow (Craft Mode), interactive session management (Play Mode), field reference, and complete genre examples. See `skills/neta-adventure/references/`.
207
215
 
208
216
  ---
@@ -231,8 +239,8 @@ In terminal environments, locale is typically controlled by:
231
239
  If you want to force a specific language for a single command, you can prefix it with the desired locale, for example:
232
240
 
233
241
  ```bash
234
- LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills make_image --help
235
- LANG=en_US.UTF-8 npx -y @talesofai/neta-skills make_image --help
242
+ LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
243
+ LANG=en_US.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
236
244
  ```
237
245
 
238
246
  ---
package/README.zh_cn.md CHANGED
@@ -140,16 +140,16 @@ export NETA_TOKEN=your_token_here
140
140
 
141
141
  ```bash
142
142
  # 查看帮助
143
- npx -y @talesofai/neta-skills --help
144
- npx -y @talesofai/neta-skills make_image --help
143
+ npx -y @talesofai/neta-skills@latest --help
144
+ npx -y @talesofai/neta-skills@latest make_image --help
145
145
 
146
146
  # 示例:生成一张图片
147
- npx -y @talesofai/neta-skills make_image \
147
+ npx -y @talesofai/neta-skills@latest make_image \
148
148
  --prompt "夜晚的赛博朋克城市,霓虹灯,高楼大厦,雨中街道" \
149
149
  --aspect "16:9"
150
150
 
151
151
  # 示例:搜索角色或元素
152
- npx -y @talesofai/neta-skills search_character_or_elementum \
152
+ npx -y @talesofai/neta-skills@latest search_character_or_elementum \
153
153
  --keywords "幻想" \
154
154
  --parent_type "character"
155
155
  ```
@@ -238,8 +238,8 @@ CLI 与 Skills 会根据系统与环境变量自动选择使用的语言:
238
238
  在需要强制指定语言时,推荐在运行命令前显式设置环境变量,例如:
239
239
 
240
240
  ```bash
241
- LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills make_image --help
242
- LANG=en_US.UTF-8 npx -y @talesofai/neta-skills make_image --help
241
+ LC_ALL=zh_CN.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
242
+ LANG=en_US.UTF-8 npx -y @talesofai/neta-skills@latest make_image --help
243
243
  ```
244
244
 
245
245
  ---
@@ -0,0 +1,41 @@
1
+ export const createCommerceApis = (client) => {
2
+ const listPlansConfig = async () => {
3
+ const res = await client.get("/v1/configs/config", {
4
+ params: {
5
+ namespace: "fe_configs",
6
+ key: "plans",
7
+ },
8
+ });
9
+ return res.data;
10
+ };
11
+ const createOrder = async (params) => {
12
+ const res = await client.post("/v1/commerce/orders", params);
13
+ return res.data;
14
+ };
15
+ const orders = async (params) => {
16
+ const res = await client.get("/v1/commerce/orders", {
17
+ params,
18
+ });
19
+ return res.data;
20
+ };
21
+ const order = async (params) => {
22
+ const res = await client.get(`/v1/commerce/orders/${params.order_uuid}`);
23
+ return res.data;
24
+ };
25
+ const pay = async (params) => {
26
+ const { order_uuid, channel, return_url, redirect_url } = params;
27
+ return client
28
+ .post(`/v1/commerce/orders/${order_uuid}/payment/${channel}`, {
29
+ redirect_url,
30
+ return_url,
31
+ })
32
+ .then((res) => res.data);
33
+ };
34
+ return {
35
+ listPlansConfig,
36
+ createOrder,
37
+ orders,
38
+ order,
39
+ pay,
40
+ };
41
+ };
package/bin/apis/index.js CHANGED
@@ -4,6 +4,7 @@ import { createActivityApis } from "./activity.js";
4
4
  import { createArtifactApis } from "./artifact.js";
5
5
  import { createAudioApis } from "./audio.js";
6
6
  import { createCollectionApis } from "./collection.js";
7
+ import { createCommerceApis } from "./commerce.js";
7
8
  import { createConfigApis } from "./config.js";
8
9
  import { createFeedsApis } from "./feeds.js";
9
10
  import { createGptApis } from "./gpt.js";
@@ -44,7 +45,9 @@ export const createApis = (option) => {
44
45
  const space = createSpaceApis(client);
45
46
  const recsys = createRecsysApis(client);
46
47
  const travelCampaign = createTravelCampaignApis(client);
48
+ const commerce = createCommerceApis(client);
47
49
  return {
50
+ baseUrl,
48
51
  tcp,
49
52
  prompt,
50
53
  artifact,
@@ -61,5 +64,6 @@ export const createApis = (option) => {
61
64
  space,
62
65
  recsys,
63
66
  travelCampaign,
67
+ commerce,
64
68
  };
65
69
  };
@@ -1,7 +1,7 @@
1
1
  name: request_adventure_campaign
2
2
  title: Get Adventure Campaign Details
3
3
  description: |
4
- Get full details of a Adventure Campaign including mission plot, task, and AI constraints.
4
+ Get full details of an Adventure Campaign including mission plot, task, and AI constraints.
5
5
 
6
6
  This is the primary command for "play mode" — load a campaign before starting a storytelling session.
7
7
 
@@ -11,7 +11,7 @@ import { resolve } from "node:path";
11
11
  import { pathToFileURL } from "node:url";
12
12
  import { Option, } from "@commander-js/extra-typings";
13
13
  import { Type } from "@sinclair/typebox";
14
- import { Default, Value } from "@sinclair/typebox/value";
14
+ import { AssertError, Value } from "@sinclair/typebox/value";
15
15
  import { createApis } from "../apis/index.js";
16
16
  import { ApiResponseError } from "../utils/errors.js";
17
17
  import { setLocale } from "../utils/parse_meta.js";
@@ -45,6 +45,7 @@ export const buildCommands = async (cli) => {
45
45
  "community",
46
46
  "character_elementum",
47
47
  "adventure_campaign",
48
+ "premium",
48
49
  ]);
49
50
  return commands.map((cmd) => {
50
51
  const command = cli.command(cmd.name);
@@ -102,7 +103,7 @@ export const buildCommands = async (cli) => {
102
103
  return null;
103
104
  });
104
105
  const type = cmd.inputSchema ?? Type.Object({});
105
- const input = Value.Decode(type, Default(type, args));
106
+ const input = Value.Parse(type, args);
106
107
  if (IS_DEV) {
107
108
  logger.debug("command: %s, params: %o", cmd.name, input);
108
109
  }
@@ -120,6 +121,17 @@ export const buildCommands = async (cli) => {
120
121
  },
121
122
  })
122
123
  .catch((e) => {
124
+ if (e instanceof AssertError) {
125
+ logger.error({
126
+ error: {
127
+ type: e.name,
128
+ message: e.message,
129
+ path: e.error?.path,
130
+ schema: e.error?.schema,
131
+ },
132
+ });
133
+ return null;
134
+ }
123
135
  if (e instanceof ApiResponseError) {
124
136
  logger.error({
125
137
  error: {
@@ -145,7 +157,7 @@ export const buildCommands = async (cli) => {
145
157
  if (!result)
146
158
  return;
147
159
  if (IS_DEV) {
148
- logger.debug(result);
160
+ logger.debug(JSON.stringify(result, null, 2));
149
161
  }
150
162
  else {
151
163
  logger.info(JSON.stringify(result));
@@ -0,0 +1,5 @@
1
+ name: create_premium_order
2
+ title: Create Premium Order
3
+ description: Create a new premium order for a subscription plan (SPU).
4
+ parameters:
5
+ spu_uuid: UUID of the premium plan SPU to purchase
@@ -0,0 +1,46 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { parseDate } from "../../utils/date.js";
3
+ import { parseMeta } from "../../utils/parse_meta.js";
4
+ import { createCommand } from "../factory.js";
5
+ const meta = parseMeta(Type.Object({
6
+ name: Type.String(),
7
+ title: Type.String(),
8
+ description: Type.String(),
9
+ parameters: Type.Object({
10
+ spu_uuid: Type.String(),
11
+ }),
12
+ }), import.meta);
13
+ export const createPremiumOrder = createCommand({
14
+ name: meta.name,
15
+ title: meta.title,
16
+ description: meta.description,
17
+ inputSchema: Type.Object({
18
+ spu_uuid: Type.String({ description: meta.parameters.spu_uuid }),
19
+ }),
20
+ }, async ({ spu_uuid }, { apis }) => {
21
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
22
+ throw new Error("This command is not supported in the current region");
23
+ }
24
+ const order = await apis.commerce.createOrder({
25
+ spu_uuid,
26
+ });
27
+ return {
28
+ order: {
29
+ uuid: order.uuid,
30
+ spu: {
31
+ uuid: order.spu.uuid,
32
+ name: order.spu.name,
33
+ price: order.spu.price,
34
+ },
35
+ status: order.status,
36
+ status_history: order.status_history.map((item) => ({
37
+ ...item,
38
+ time: parseDate(item.time).format(),
39
+ })),
40
+ price: order.price,
41
+ valid_until: parseDate(order.valid_until).format(),
42
+ ctime: parseDate(order.ctime).format(),
43
+ mtime: parseDate(order.mtime).format(),
44
+ },
45
+ };
46
+ });
@@ -0,0 +1,5 @@
1
+ name: create_premium_order
2
+ title: 创建会员订单
3
+ description: 为订阅套餐(SPU)创建新的会员订单。
4
+ parameters:
5
+ spu_uuid: 要购买的会员套餐 SPU 的 UUID
@@ -0,0 +1,3 @@
1
+ name: get_current_premium_plan
2
+ title: Get Current Premium Plan
3
+ description: Get the signed-in user's current premium tier and subscription end time.
@@ -0,0 +1,32 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { parseDate } from "../../utils/date.js";
3
+ import { parseMeta } from "../../utils/parse_meta.js";
4
+ import { createCommand } from "../factory.js";
5
+ const PlanningMap = {
6
+ 0: "Basic",
7
+ 1: "Starter",
8
+ 2: "Pro",
9
+ 3: "Master",
10
+ };
11
+ const meta = parseMeta(Type.Object({
12
+ name: Type.String(),
13
+ title: Type.String(),
14
+ description: Type.String(),
15
+ }), import.meta);
16
+ export const getCurrentPremiumPlan = createCommand({
17
+ name: meta.name,
18
+ title: meta.title,
19
+ description: meta.description,
20
+ }, async (_, { apis }) => {
21
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
22
+ throw new Error("This command is not supported in the current region");
23
+ }
24
+ const user = await apis.user.me();
25
+ const level = user.properties?.vip_level ?? 0;
26
+ return {
27
+ plan: PlanningMap[level],
28
+ until: user.properties?.vip_until
29
+ ? parseDate(user.properties.vip_until).format()
30
+ : null,
31
+ };
32
+ });
@@ -0,0 +1,3 @@
1
+ name: get_current_premium_plan
2
+ title: 当前会员方案
3
+ description: 获取当前登录用户的会员档位与到期时间。
@@ -0,0 +1,5 @@
1
+ name: get_premium_order
2
+ title: Get Premium Order
3
+ description: Fetch details of a premium order by its UUID.
4
+ parameters:
5
+ order_uuid: Premium order UUID
@@ -0,0 +1,44 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { parseDate } from "../../utils/date.js";
3
+ import { parseMeta } from "../../utils/parse_meta.js";
4
+ import { createCommand } from "../factory.js";
5
+ const meta = parseMeta(Type.Object({
6
+ name: Type.String(),
7
+ title: Type.String(),
8
+ description: Type.String(),
9
+ parameters: Type.Object({
10
+ order_uuid: Type.String(),
11
+ }),
12
+ }), import.meta);
13
+ export const getPremiumOrder = createCommand({
14
+ name: meta.name,
15
+ title: meta.title,
16
+ description: meta.description,
17
+ inputSchema: Type.Object({
18
+ order_uuid: Type.String({ description: meta.parameters.order_uuid }),
19
+ }),
20
+ }, async ({ order_uuid }, { apis }) => {
21
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
22
+ throw new Error("This command is not supported in the current region");
23
+ }
24
+ const order = await apis.commerce.order({ order_uuid });
25
+ return {
26
+ order: {
27
+ uuid: order.uuid,
28
+ spu: {
29
+ uuid: order.spu.uuid,
30
+ name: order.spu.name,
31
+ price: order.spu.price,
32
+ },
33
+ status: order.status,
34
+ status_history: order.status_history.map((item) => ({
35
+ ...item,
36
+ time: parseDate(item.time).format(),
37
+ })),
38
+ price: order.price,
39
+ valid_until: parseDate(order.valid_until).format(),
40
+ ctime: parseDate(order.ctime).format(),
41
+ mtime: parseDate(order.mtime).format(),
42
+ },
43
+ };
44
+ });
@@ -0,0 +1,5 @@
1
+ name: get_premium_order
2
+ title: 获取会员订单
3
+ description: 根据订单 UUID 查询会员订单详情。
4
+ parameters:
5
+ order_uuid: 会员订单 UUID
@@ -0,0 +1,6 @@
1
+ name: list_premium_orders
2
+ title: List Premium Orders
3
+ description: List your premium orders with pagination.
4
+ parameters:
5
+ page_index: Zero-based page index
6
+ page_size: Page size (1–50)
@@ -0,0 +1,59 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { parseDate } from "../../utils/date.js";
3
+ import { parseMeta } from "../../utils/parse_meta.js";
4
+ import { createCommand } from "../factory.js";
5
+ const meta = parseMeta(Type.Object({
6
+ name: Type.String(),
7
+ title: Type.String(),
8
+ description: Type.String(),
9
+ parameters: Type.Object({
10
+ page_index: Type.String(),
11
+ page_size: Type.String(),
12
+ }),
13
+ }), import.meta);
14
+ export const listPremiumOrders = createCommand({
15
+ name: meta.name,
16
+ title: meta.title,
17
+ description: meta.description,
18
+ inputSchema: Type.Object({
19
+ page_index: Type.Integer({
20
+ minimum: 0,
21
+ default: 0,
22
+ description: meta.parameters.page_index,
23
+ }),
24
+ page_size: Type.Integer({
25
+ minimum: 1,
26
+ maximum: 50,
27
+ default: 20,
28
+ description: meta.parameters.page_size,
29
+ }),
30
+ }),
31
+ }, async ({ page_index, page_size }, { apis }) => {
32
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
33
+ throw new Error("This command is not supported in the current region");
34
+ }
35
+ const { list, total } = await apis.commerce.orders({
36
+ page_index,
37
+ page_size,
38
+ });
39
+ return {
40
+ total,
41
+ orders: list.map((order) => ({
42
+ uuid: order.uuid,
43
+ spu: {
44
+ uuid: order.spu.uuid,
45
+ name: order.spu.name,
46
+ price: order.spu.price,
47
+ },
48
+ status: order.status,
49
+ status_history: order.status_history.map((item) => ({
50
+ ...item,
51
+ time: parseDate(item.time).format(),
52
+ })),
53
+ price: order.price,
54
+ valid_until: parseDate(order.valid_until).format(),
55
+ ctime: parseDate(order.ctime).format(),
56
+ mtime: parseDate(order.mtime).format(),
57
+ })),
58
+ };
59
+ });
@@ -0,0 +1,6 @@
1
+ name: list_premium_orders
2
+ title: 会员订单列表
3
+ description: 分页列出当前用户的会员订单。
4
+ parameters:
5
+ page_index: 从 0 开始的页码
6
+ page_size: 每页条数(1–50)
@@ -0,0 +1,3 @@
1
+ name: list_premium_plans
2
+ title: List Premium Subscription Plans
3
+ description: List available premium subscription plans and pricing (locale-specific config).
@@ -0,0 +1,67 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { Value } from "@sinclair/typebox/value";
3
+ import { safeParseJson } from "../../utils/json.js";
4
+ import { parseMeta } from "../../utils/parse_meta.js";
5
+ import { createCommand } from "../factory.js";
6
+ const meta = parseMeta(Type.Object({
7
+ name: Type.String(),
8
+ title: Type.String(),
9
+ description: Type.String(),
10
+ }), import.meta);
11
+ const PlanBasicInfo = Type.Object({
12
+ descriptions: Type.Array(Type.String()),
13
+ infoPopup: Type.Object({
14
+ title: Type.String(),
15
+ content: Type.String(),
16
+ }),
17
+ });
18
+ const Plan = Type.Composite([
19
+ PlanBasicInfo,
20
+ Type.Object({
21
+ price: Type.Object({
22
+ monthly: Type.Number(),
23
+ monthlyOff: Type.Number(),
24
+ monthlyOriginal: Type.Number(),
25
+ yearly: Type.Number(),
26
+ yearlyTotal: Type.Number(),
27
+ off: Type.Number(),
28
+ }),
29
+ spu: Type.Object({
30
+ monthly: Type.Optional(Type.String()),
31
+ yearly: Type.Optional(Type.String()),
32
+ }),
33
+ }),
34
+ ]);
35
+ const PlansConfig = Type.Object({
36
+ "en-US": Type.Optional(Type.Record(Type.Union([
37
+ Type.Literal("Master"),
38
+ Type.Literal("Pro"),
39
+ Type.Literal("Starter"),
40
+ ]), Type.Optional(Plan))),
41
+ });
42
+ export const listPremiumPlans = createCommand({
43
+ name: meta.name,
44
+ title: meta.title,
45
+ description: meta.description,
46
+ }, async (_, { apis }) => {
47
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
48
+ throw new Error("This command is not supported in the current region");
49
+ }
50
+ const plansConfigValue = await apis.commerce.listPlansConfig();
51
+ if (!plansConfigValue || plansConfigValue.type !== "json") {
52
+ throw new Error("Premium subscription plans config not found");
53
+ }
54
+ const json = safeParseJson(plansConfigValue.value);
55
+ try {
56
+ const plansConfig = Value.Parse(PlansConfig, json);
57
+ const plans = plansConfig["en-US"] ?? {};
58
+ return {
59
+ plans,
60
+ };
61
+ }
62
+ catch (error) {
63
+ throw new Error("Premium subscription plans config is invalid", {
64
+ cause: error,
65
+ });
66
+ }
67
+ });
@@ -0,0 +1,3 @@
1
+ name: list_premium_plans
2
+ title: 会员订阅方案列表
3
+ description: 列出可用的会员订阅方案与价格(按语言环境的配置)。
@@ -0,0 +1,6 @@
1
+ name: pay_premium_order
2
+ title: Pay Premium Order
3
+ description: Start payment for an unpaid premium order using the given channel.
4
+ parameters:
5
+ order_uuid: Premium order UUID to pay
6
+ channel: Payment channel (e.g. stripe-checkout)
@@ -0,0 +1,44 @@
1
+ import { Type } from "@sinclair/typebox";
2
+ import { parseDate } from "../../utils/date.js";
3
+ import { parseMeta } from "../../utils/parse_meta.js";
4
+ import { createCommand } from "../factory.js";
5
+ const meta = parseMeta(Type.Object({
6
+ name: Type.String(),
7
+ title: Type.String(),
8
+ description: Type.String(),
9
+ parameters: Type.Object({
10
+ order_uuid: Type.String(),
11
+ channel: Type.String(),
12
+ }),
13
+ }), import.meta);
14
+ export const payPremiumOrder = createCommand({
15
+ name: meta.name,
16
+ title: meta.title,
17
+ description: meta.description,
18
+ inputSchema: Type.Object({
19
+ order_uuid: Type.String({ description: meta.parameters.order_uuid }),
20
+ channel: Type.Union([Type.Literal("stripe-checkout")], {
21
+ description: meta.parameters.channel,
22
+ }),
23
+ }),
24
+ }, async ({ order_uuid, channel }, { apis }) => {
25
+ if (!apis.baseUrl.endsWith("talesofai.com")) {
26
+ throw new Error("This command is not supported in the current region");
27
+ }
28
+ const order = await apis.commerce.order({ order_uuid });
29
+ if (order.status !== "UNPAID") {
30
+ throw new Error("Order is not unpaid");
31
+ }
32
+ if (parseDate(order.valid_until).isBefore(Date.now())) {
33
+ throw new Error("Order is expired");
34
+ }
35
+ const result = await apis.commerce.pay({
36
+ order_uuid,
37
+ channel,
38
+ return_url: "https://app.neta.art/subscribe/callback",
39
+ });
40
+ return {
41
+ checkout_session_url: result.checkout_session_url,
42
+ checkout_session_id: result.checkout_session_id,
43
+ };
44
+ });
@@ -0,0 +1,6 @@
1
+ name: pay_premium_order
2
+ title: 支付会员订单
3
+ description: 通过指定支付渠道为待支付的会员订单发起支付。
4
+ parameters:
5
+ order_uuid: 要支付的会员订单 UUID
6
+ channel: 支付渠道(如 stripe-checkout)