@kevisual/router 0.0.74 → 0.0.76

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.
@@ -1,6 +1,7 @@
1
1
  import { app, createSkill, tool } from '../app.ts';
2
2
  import * as docs from '../gen/index.ts'
3
3
  import * as pkgs from '../../package.json' assert { type: 'json' };
4
+ import z from 'zod';
4
5
  app.route({
5
6
  path: 'router-skill',
6
7
  key: 'create-route',
@@ -32,14 +33,47 @@ app.route({
32
33
  }
33
34
  }).addTo(app);
34
35
 
35
- // 调用router应用 path router-skill key version
36
+ // 获取最新router版本号
36
37
  app.route({
37
38
  path: 'router-skill',
38
39
  key: 'version',
39
- description: '获取路由技能版本',
40
+ description: '获取最新router版本号',
40
41
  middleware: ['auth'],
42
+ metadata: {
43
+ tags: ['opencode'],
44
+ ...createSkill({
45
+ skill: 'router-skill-version',
46
+ title: '获取最新router版本号',
47
+ summary: '获取最新router版本号',
48
+ args: {}
49
+ })
50
+ },
41
51
  }).define(async (ctx) => {
42
52
  ctx.body = {
43
53
  content: pkgs.version || 'unknown'
44
54
  }
45
- }).addTo(app);
55
+ }).addTo(app);
56
+
57
+ // 执行技能test-route-skill,name为abearxiong
58
+ app.route({
59
+ path: 'route-skill',
60
+ key: 'test',
61
+ description: '测试路由技能',
62
+ middleware: ['auth'],
63
+ metadata: {
64
+ tags: ['opencode'],
65
+ ...createSkill({
66
+ skill: 'test-route-skill',
67
+ title: '测试路由技能',
68
+ summary: '测试路由技能是否正常工作',
69
+ args: z.object({
70
+ name: z.string().describe('名字'),
71
+ })
72
+ })
73
+ },
74
+ }).define(async (ctx) => {
75
+ const name = ctx.query.name || 'unknown';
76
+ ctx.body = {
77
+ content: '测试成功,你好 ' + name
78
+ }
79
+ }).addTo(app)
package/dist/app.js CHANGED
@@ -16745,6 +16745,9 @@ function date4(params) {
16745
16745
 
16746
16746
  // node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
16747
16747
  config(en_default());
16748
+ // node_modules/.pnpm/zod@4.3.6/node_modules/zod/index.js
16749
+ var zod_default = exports_external;
16750
+
16748
16751
  // node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
16749
16752
  import { webcrypto as crypto } from "node:crypto";
16750
16753
  var POOL_SIZE_MULTIPLIER = 128;
@@ -16799,6 +16802,12 @@ var tool = {
16799
16802
  schema: exports_external
16800
16803
  };
16801
16804
  var createSkill = (skill) => {
16805
+ if (skill.tags) {
16806
+ const hasOpencode = skill.tags.includes("opencode");
16807
+ if (!hasOpencode) {
16808
+ skill.tags.push("opencode");
16809
+ }
16810
+ }
16802
16811
  return {
16803
16812
  args: {},
16804
16813
  ...skill
@@ -16815,7 +16824,6 @@ class Route {
16815
16824
  metadata;
16816
16825
  middleware;
16817
16826
  type = "route";
16818
- data;
16819
16827
  isDebug;
16820
16828
  constructor(path = "", key = "", opts) {
16821
16829
  if (!path) {
@@ -16907,18 +16915,21 @@ class Route {
16907
16915
  addTo(router, opts) {
16908
16916
  router.add(this, opts);
16909
16917
  }
16910
- setData(data) {
16911
- this.data = data;
16912
- return this;
16913
- }
16914
16918
  throw(...args) {
16915
16919
  throw new CustomError(...args);
16916
16920
  }
16917
16921
  }
16922
+ var extractArgs = (args) => {
16923
+ if (args && typeof args === "object" && typeof args.shape === "object") {
16924
+ return args.shape;
16925
+ }
16926
+ return args || {};
16927
+ };
16918
16928
  var toJSONSchema2 = (route) => {
16919
16929
  const pickValues = pick(route, pickValue);
16920
16930
  if (pickValues?.metadata?.args) {
16921
- const args = pickValues.metadata.args;
16931
+ let args = pickValues.metadata.args;
16932
+ args = extractArgs(args);
16922
16933
  const keys = Object.keys(args);
16923
16934
  const newArgs = {};
16924
16935
  for (let key of keys) {
@@ -16937,6 +16948,10 @@ var fromJSONSchema2 = (route) => {
16937
16948
  const args = route?.metadata?.args;
16938
16949
  if (!args)
16939
16950
  return route;
16951
+ if (args["$schema"] || args.type === "object" && args.properties && typeof args.properties === "object") {
16952
+ route.metadata.args = exports_external.fromJSONSchema(args);
16953
+ return route;
16954
+ }
16940
16955
  const keys = Object.keys(args);
16941
16956
  const newArgs = {};
16942
16957
  for (let key of keys) {
@@ -19175,8 +19190,12 @@ var addCallFn = (app2) => {
19175
19190
  tags: ["opencode"],
19176
19191
  ...createSkill({
19177
19192
  skill: "call-app",
19178
- title: "调用app应用",
19179
- summary: "调用router的应用, 参数path, key, payload",
19193
+ title: "调用app应用,非技能模块",
19194
+ summary: `调用router的应用(非技能模块),适用于需要直接调用应用而不是技能的场景
19195
+ 条件1: 参数path(string), key(string), payload(object)
19196
+ 条件2: 当前的应用调用的模式不是技能
19197
+
19198
+ `,
19180
19199
  args: {
19181
19200
  path: tool.schema.string().describe("应用路径,例如 cnb"),
19182
19201
  key: tool.schema.string().optional().describe("应用key,例如 list-repos"),
@@ -19196,6 +19215,7 @@ var addCallFn = (app2) => {
19196
19215
  }).addTo(app2);
19197
19216
  };
19198
19217
  var createRouterAgentPluginFn = (opts) => {
19218
+ new Promise((resolve) => setTimeout(resolve, 100));
19199
19219
  let router = opts?.router;
19200
19220
  if (!router) {
19201
19221
  const app2 = useContextKey("app");
@@ -19213,6 +19233,9 @@ var createRouterAgentPluginFn = (opts) => {
19213
19233
  const _routes = filter(router.routes, opts?.query || "");
19214
19234
  const routes = _routes.filter((r) => {
19215
19235
  const metadata = r.metadata;
19236
+ if (metadata && metadata.skill && metadata.summary) {
19237
+ return true;
19238
+ }
19216
19239
  if (metadata && metadata.tags && metadata.tags.includes("opencode")) {
19217
19240
  return !!metadata.skill;
19218
19241
  }
@@ -19226,15 +19249,16 @@ var createRouterAgentPluginFn = (opts) => {
19226
19249
  tool: {
19227
19250
  ...routes.reduce((acc, route) => {
19228
19251
  const metadata = route.metadata;
19252
+ let args = extractArgs2(metadata?.args);
19229
19253
  acc[metadata.skill] = {
19230
19254
  name: metadata.title || metadata.skill,
19231
19255
  description: metadata.summary || "",
19232
- args: metadata.args || {},
19233
- async execute(args) {
19256
+ args,
19257
+ async execute(args2) {
19234
19258
  const res = await router.run({
19235
19259
  path: route.path,
19236
19260
  key: route.key,
19237
- payload: args
19261
+ payload: args2
19238
19262
  }, { appId: router.appId });
19239
19263
  if (res.code === 200) {
19240
19264
  if (res.data?.content) {
@@ -19261,6 +19285,12 @@ var createRouterAgentPluginFn = (opts) => {
19261
19285
  };
19262
19286
  return AgentPlugin;
19263
19287
  };
19288
+ var extractArgs2 = (args) => {
19289
+ if (args && typeof args === "object" && typeof args.shape === "object") {
19290
+ return args.shape;
19291
+ }
19292
+ return args || {};
19293
+ };
19264
19294
 
19265
19295
  // agent/gen/index.ts
19266
19296
  var readme = `# router
@@ -19453,7 +19483,7 @@ app
19453
19483
  10. **中间件找不到会返回 404**,错误信息中会包含找不到的中间件列表。
19454
19484
  `;
19455
19485
  // package.json
19456
- var version2 = "0.0.74";
19486
+ var version2 = "0.0.76";
19457
19487
 
19458
19488
  // agent/routes/route-create.ts
19459
19489
  app.route({
@@ -19493,13 +19523,44 @@ app.route({
19493
19523
  app.route({
19494
19524
  path: "router-skill",
19495
19525
  key: "version",
19496
- description: "获取路由技能版本",
19497
- middleware: ["auth"]
19526
+ description: "获取最新router版本号",
19527
+ middleware: ["auth"],
19528
+ metadata: {
19529
+ tags: ["opencode"],
19530
+ ...createSkill({
19531
+ skill: "router-skill-version",
19532
+ title: "获取最新router版本号",
19533
+ summary: "获取最新router版本号",
19534
+ args: {}
19535
+ })
19536
+ }
19498
19537
  }).define(async (ctx) => {
19499
19538
  ctx.body = {
19500
19539
  content: version2 || "unknown"
19501
19540
  };
19502
19541
  }).addTo(app);
19542
+ app.route({
19543
+ path: "route-skill",
19544
+ key: "test",
19545
+ description: "测试路由技能",
19546
+ middleware: ["auth"],
19547
+ metadata: {
19548
+ tags: ["opencode"],
19549
+ ...createSkill({
19550
+ skill: "test-route-skill",
19551
+ title: "测试路由技能",
19552
+ summary: "测试路由技能是否正常工作",
19553
+ args: zod_default.object({
19554
+ name: zod_default.string().describe("名字")
19555
+ })
19556
+ })
19557
+ }
19558
+ }).define(async (ctx) => {
19559
+ const name = ctx.query.name || "unknown";
19560
+ ctx.body = {
19561
+ content: "测试成功,你好 " + name
19562
+ };
19563
+ }).addTo(app);
19503
19564
 
19504
19565
  // agent/routes/index.ts
19505
19566
  if (!app.hasRoute("auth", "")) {
@@ -150,7 +150,6 @@ declare class Route<U = {
150
150
  metadata?: T;
151
151
  middleware?: RouteMiddleware[];
152
152
  type?: string;
153
- data?: any;
154
153
  /**
155
154
  * 是否开启debug,开启后会打印错误信息
156
155
  */
@@ -175,7 +174,6 @@ declare class Route<U = {
175
174
  add: (route: Route) => void;
176
175
  [key: string]: any;
177
176
  }, opts?: AddOpts): void;
178
- setData(data: any): this;
179
177
  throw(code?: number | string, message?: string, tips?: string): void;
180
178
  }
181
179
  /**
@@ -719,5 +717,12 @@ declare const createRouterAgentPluginFn: (opts?: {
719
717
  hooks?: (plugin: PluginInput) => Promise<Hooks>;
720
718
  }) => Plugin;
721
719
  declare const usePluginInput: () => PluginInput;
720
+ /**
721
+ * 如果args是z.object类型,拆分第一个Object的属性,比如z.object({ name: z.string(), age: z.number() }),拆分成{name: z.string(), age: z.number()}
722
+ * 如果args是普通对象,直接返回
723
+ * @param args
724
+ * @returns
725
+ */
726
+ declare const extractArgs: (args: any) => any;
722
727
 
723
- export { addCallFn, createRouterAgentPluginFn, usePluginInput };
728
+ export { addCallFn, createRouterAgentPluginFn, extractArgs, usePluginInput };
package/dist/opencode.js CHANGED
@@ -14339,6 +14339,12 @@ var tool = {
14339
14339
  schema: exports_external
14340
14340
  };
14341
14341
  var createSkill = (skill) => {
14342
+ if (skill.tags) {
14343
+ const hasOpencode = skill.tags.includes("opencode");
14344
+ if (!hasOpencode) {
14345
+ skill.tags.push("opencode");
14346
+ }
14347
+ }
14342
14348
  return {
14343
14349
  args: {},
14344
14350
  ...skill
@@ -14699,8 +14705,12 @@ var addCallFn = (app) => {
14699
14705
  tags: ["opencode"],
14700
14706
  ...createSkill({
14701
14707
  skill: "call-app",
14702
- title: "调用app应用",
14703
- summary: "调用router的应用, 参数path, key, payload",
14708
+ title: "调用app应用,非技能模块",
14709
+ summary: `调用router的应用(非技能模块),适用于需要直接调用应用而不是技能的场景
14710
+ 条件1: 参数path(string), key(string), payload(object)
14711
+ 条件2: 当前的应用调用的模式不是技能
14712
+
14713
+ `,
14704
14714
  args: {
14705
14715
  path: tool.schema.string().describe("应用路径,例如 cnb"),
14706
14716
  key: tool.schema.string().optional().describe("应用key,例如 list-repos"),
@@ -14720,6 +14730,7 @@ var addCallFn = (app) => {
14720
14730
  }).addTo(app);
14721
14731
  };
14722
14732
  var createRouterAgentPluginFn = (opts) => {
14733
+ new Promise((resolve) => setTimeout(resolve, 100));
14723
14734
  let router = opts?.router;
14724
14735
  if (!router) {
14725
14736
  const app = useContextKey("app");
@@ -14737,6 +14748,9 @@ var createRouterAgentPluginFn = (opts) => {
14737
14748
  const _routes = filter(router.routes, opts?.query || "");
14738
14749
  const routes = _routes.filter((r) => {
14739
14750
  const metadata = r.metadata;
14751
+ if (metadata && metadata.skill && metadata.summary) {
14752
+ return true;
14753
+ }
14740
14754
  if (metadata && metadata.tags && metadata.tags.includes("opencode")) {
14741
14755
  return !!metadata.skill;
14742
14756
  }
@@ -14750,15 +14764,16 @@ var createRouterAgentPluginFn = (opts) => {
14750
14764
  tool: {
14751
14765
  ...routes.reduce((acc, route) => {
14752
14766
  const metadata = route.metadata;
14767
+ let args = extractArgs(metadata?.args);
14753
14768
  acc[metadata.skill] = {
14754
14769
  name: metadata.title || metadata.skill,
14755
14770
  description: metadata.summary || "",
14756
- args: metadata.args || {},
14757
- async execute(args) {
14771
+ args,
14772
+ async execute(args2) {
14758
14773
  const res = await router.run({
14759
14774
  path: route.path,
14760
14775
  key: route.key,
14761
- payload: args
14776
+ payload: args2
14762
14777
  }, { appId: router.appId });
14763
14778
  if (res.code === 200) {
14764
14779
  if (res.data?.content) {
@@ -14788,8 +14803,15 @@ var createRouterAgentPluginFn = (opts) => {
14788
14803
  var usePluginInput = () => {
14789
14804
  return useContextKey("plugin-input");
14790
14805
  };
14806
+ var extractArgs = (args) => {
14807
+ if (args && typeof args === "object" && typeof args.shape === "object") {
14808
+ return args.shape;
14809
+ }
14810
+ return args || {};
14811
+ };
14791
14812
  export {
14792
14813
  usePluginInput,
14814
+ extractArgs,
14793
14815
  createRouterAgentPluginFn,
14794
14816
  addCallFn
14795
14817
  };
@@ -149,6 +149,7 @@ type Skill<T = SimpleObject$1> = {
149
149
  skill: string;
150
150
  title: string;
151
151
  summary?: string;
152
+ tags?: string[];
152
153
  args?: {
153
154
  [key: string]: any;
154
155
  };
@@ -177,7 +178,6 @@ declare class Route<U = {
177
178
  metadata?: T;
178
179
  middleware?: RouteMiddleware[];
179
180
  type?: string;
180
- data?: any;
181
181
  /**
182
182
  * 是否开启debug,开启后会打印错误信息
183
183
  */
@@ -202,7 +202,6 @@ declare class Route<U = {
202
202
  add: (route: Route) => void;
203
203
  [key: string]: any;
204
204
  }, opts?: AddOpts): void;
205
- setData(data: any): this;
206
205
  throw(code?: number | string, message?: string, tips?: string): void;
207
206
  }
208
207
  declare const toJSONSchema: (route: RouteInfo) => Pick<RouteInfo, "path" | "key" | "id" | "description" | "type" | "middleware" | "metadata">;
@@ -13966,6 +13966,12 @@ var tool = {
13966
13966
  schema: exports_external
13967
13967
  };
13968
13968
  var createSkill = (skill) => {
13969
+ if (skill.tags) {
13970
+ const hasOpencode = skill.tags.includes("opencode");
13971
+ if (!hasOpencode) {
13972
+ skill.tags.push("opencode");
13973
+ }
13974
+ }
13969
13975
  return {
13970
13976
  args: {},
13971
13977
  ...skill
@@ -13982,7 +13988,6 @@ class Route {
13982
13988
  metadata;
13983
13989
  middleware;
13984
13990
  type = "route";
13985
- data;
13986
13991
  isDebug;
13987
13992
  constructor(path = "", key = "", opts) {
13988
13993
  if (!path) {
@@ -14074,18 +14079,21 @@ class Route {
14074
14079
  addTo(router, opts) {
14075
14080
  router.add(this, opts);
14076
14081
  }
14077
- setData(data) {
14078
- this.data = data;
14079
- return this;
14080
- }
14081
14082
  throw(...args) {
14082
14083
  throw new CustomError(...args);
14083
14084
  }
14084
14085
  }
14086
+ var extractArgs = (args) => {
14087
+ if (args && typeof args === "object" && typeof args.shape === "object") {
14088
+ return args.shape;
14089
+ }
14090
+ return args || {};
14091
+ };
14085
14092
  var toJSONSchema2 = (route) => {
14086
14093
  const pickValues = pick(route, pickValue);
14087
14094
  if (pickValues?.metadata?.args) {
14088
- const args = pickValues.metadata.args;
14095
+ let args = pickValues.metadata.args;
14096
+ args = extractArgs(args);
14089
14097
  const keys = Object.keys(args);
14090
14098
  const newArgs = {};
14091
14099
  for (let key of keys) {
@@ -14104,6 +14112,10 @@ var fromJSONSchema2 = (route) => {
14104
14112
  const args = route?.metadata?.args;
14105
14113
  if (!args)
14106
14114
  return route;
14115
+ if (args["$schema"] || args.type === "object" && args.properties && typeof args.properties === "object") {
14116
+ route.metadata.args = exports_external.fromJSONSchema(args);
14117
+ return route;
14118
+ }
14107
14119
  const keys = Object.keys(args);
14108
14120
  const newArgs = {};
14109
14121
  for (let key of keys) {
@@ -147,7 +147,6 @@ declare class Route<U = {
147
147
  metadata?: T;
148
148
  middleware?: RouteMiddleware[];
149
149
  type?: string;
150
- data?: any;
151
150
  /**
152
151
  * 是否开启debug,开启后会打印错误信息
153
152
  */
@@ -172,7 +171,6 @@ declare class Route<U = {
172
171
  add: (route: Route) => void;
173
172
  [key: string]: any;
174
173
  }, opts?: AddOpts): void;
175
- setData(data: any): this;
176
174
  throw(code?: number | string, message?: string, tips?: string): void;
177
175
  }
178
176
  /**
package/dist/router.d.ts CHANGED
@@ -155,6 +155,7 @@ type Skill<T = SimpleObject$1> = {
155
155
  skill: string;
156
156
  title: string;
157
157
  summary?: string;
158
+ tags?: string[];
158
159
  args?: {
159
160
  [key: string]: any;
160
161
  };
@@ -183,7 +184,6 @@ declare class Route<U = {
183
184
  metadata?: T;
184
185
  middleware?: RouteMiddleware[];
185
186
  type?: string;
186
- data?: any;
187
187
  /**
188
188
  * 是否开启debug,开启后会打印错误信息
189
189
  */
@@ -208,7 +208,6 @@ declare class Route<U = {
208
208
  add: (route: Route) => void;
209
209
  [key: string]: any;
210
210
  }, opts?: AddOpts): void;
211
- setData(data: any): this;
212
211
  throw(code?: number | string, message?: string, tips?: string): void;
213
212
  }
214
213
  declare const toJSONSchema: (route: RouteInfo) => Pick<RouteInfo, "path" | "key" | "id" | "description" | "type" | "middleware" | "metadata">;
package/dist/router.js CHANGED
@@ -16799,6 +16799,12 @@ var tool = {
16799
16799
  schema: exports_external
16800
16800
  };
16801
16801
  var createSkill = (skill) => {
16802
+ if (skill.tags) {
16803
+ const hasOpencode = skill.tags.includes("opencode");
16804
+ if (!hasOpencode) {
16805
+ skill.tags.push("opencode");
16806
+ }
16807
+ }
16802
16808
  return {
16803
16809
  args: {},
16804
16810
  ...skill
@@ -16815,7 +16821,6 @@ class Route {
16815
16821
  metadata;
16816
16822
  middleware;
16817
16823
  type = "route";
16818
- data;
16819
16824
  isDebug;
16820
16825
  constructor(path = "", key = "", opts) {
16821
16826
  if (!path) {
@@ -16907,18 +16912,21 @@ class Route {
16907
16912
  addTo(router, opts) {
16908
16913
  router.add(this, opts);
16909
16914
  }
16910
- setData(data) {
16911
- this.data = data;
16912
- return this;
16913
- }
16914
16915
  throw(...args) {
16915
16916
  throw new CustomError(...args);
16916
16917
  }
16917
16918
  }
16919
+ var extractArgs = (args) => {
16920
+ if (args && typeof args === "object" && typeof args.shape === "object") {
16921
+ return args.shape;
16922
+ }
16923
+ return args || {};
16924
+ };
16918
16925
  var toJSONSchema2 = (route) => {
16919
16926
  const pickValues = pick(route, pickValue);
16920
16927
  if (pickValues?.metadata?.args) {
16921
- const args = pickValues.metadata.args;
16928
+ let args = pickValues.metadata.args;
16929
+ args = extractArgs(args);
16922
16930
  const keys = Object.keys(args);
16923
16931
  const newArgs = {};
16924
16932
  for (let key of keys) {
@@ -16937,6 +16945,10 @@ var fromJSONSchema2 = (route) => {
16937
16945
  const args = route?.metadata?.args;
16938
16946
  if (!args)
16939
16947
  return route;
16948
+ if (args["$schema"] || args.type === "object" && args.properties && typeof args.properties === "object") {
16949
+ route.metadata.args = exports_external.fromJSONSchema(args);
16950
+ return route;
16951
+ }
16940
16952
  const keys = Object.keys(args);
16941
16953
  const newArgs = {};
16942
16954
  for (let key of keys) {
package/dist/ws.d.ts CHANGED
@@ -197,7 +197,6 @@ declare class Route<U = {
197
197
  metadata?: T;
198
198
  middleware?: RouteMiddleware[];
199
199
  type?: string;
200
- data?: any;
201
200
  /**
202
201
  * 是否开启debug,开启后会打印错误信息
203
202
  */
@@ -222,7 +221,6 @@ declare class Route<U = {
222
221
  add: (route: Route) => void;
223
222
  [key: string]: any;
224
223
  }, opts?: AddOpts): void;
225
- setData(data: any): this;
226
224
  throw(code?: number | string, message?: string, tips?: string): void;
227
225
  }
228
226
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@kevisual/router",
4
- "version": "0.0.74",
4
+ "version": "0.0.76",
5
5
  "description": "",
6
6
  "type": "module",
7
7
  "main": "./dist/router.js",
@@ -21,14 +21,13 @@
21
21
  "keywords": [],
22
22
  "author": "abearxiong",
23
23
  "license": "MIT",
24
- "packageManager": "pnpm@10.30.0",
25
24
  "devDependencies": {
26
25
  "@kevisual/code-builder": "^0.0.6",
27
26
  "@kevisual/context": "^0.0.6",
28
27
  "@kevisual/dts": "^0.0.4",
29
28
  "@kevisual/js-filter": "^0.0.5",
30
29
  "@kevisual/local-proxy": "^0.0.8",
31
- "@kevisual/query": "^0.0.43",
30
+ "@kevisual/query": "^0.0.46",
32
31
  "@kevisual/use-config": "^1.0.30",
33
32
  "@opencode-ai/plugin": "^1.2.6",
34
33
  "@types/bun": "^1.3.9",
package/src/opencode.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useContextKey } from '@kevisual/context'
2
- import { createSkill, type QueryRouterServer, tool, type QueryRouter, type Skill } from './route.ts'
2
+ import { createSkill, type QueryRouterServer, tool, type Skill } from './route.ts'
3
3
  import { type App } from './app.ts'
4
4
  import { PluginInput, type Plugin, Hooks } from "@opencode-ai/plugin"
5
5
 
@@ -15,8 +15,12 @@ export const addCallFn = (app: App) => {
15
15
  tags: ['opencode'],
16
16
  ...createSkill({
17
17
  skill: 'call-app',
18
- title: '调用app应用',
19
- summary: '调用router的应用, 参数path, key, payload',
18
+ title: '调用app应用,非技能模块',
19
+ summary: `调用router的应用(非技能模块),适用于需要直接调用应用而不是技能的场景
20
+ 条件1: 参数path(string), key(string), payload(object)
21
+ 条件2: 当前的应用调用的模式不是技能
22
+
23
+ `,
20
24
  args: {
21
25
  path: tool.schema.string().describe('应用路径,例如 cnb'),
22
26
  key: tool.schema.string().optional().describe('应用key,例如 list-repos'),
@@ -42,7 +46,9 @@ export const createRouterAgentPluginFn = (opts?: {
42
46
  query?: string,
43
47
  hooks?: (plugin: PluginInput) => Promise<Hooks>
44
48
  }) => {
49
+ new Promise(resolve => setTimeout(resolve, 100)) // 等待路由加载
45
50
  let router = opts?.router
51
+
46
52
  if (!router) {
47
53
  const app = useContextKey<App>('app')
48
54
  router = app
@@ -59,13 +65,15 @@ export const createRouterAgentPluginFn = (opts?: {
59
65
  const _routes = filter(router.routes, opts?.query || '')
60
66
  const routes = _routes.filter(r => {
61
67
  const metadata = r.metadata as Skill
68
+ if (metadata && metadata.skill && metadata.summary) {
69
+ return true
70
+ }
62
71
  if (metadata && metadata.tags && metadata.tags.includes('opencode')) {
63
72
  return !!metadata.skill
64
73
  }
65
74
  return false
66
75
  });
67
-
68
- // opencode run "查看系统信息"
76
+ // opencode run "使用技能查看系统信息"
69
77
  const AgentPlugin: Plugin = async (pluginInput) => {
70
78
  useContextKey<PluginInput>('plugin-input', () => pluginInput, true)
71
79
  const hooks = opts?.hooks ? await opts.hooks(pluginInput) : {}
@@ -74,10 +82,11 @@ export const createRouterAgentPluginFn = (opts?: {
74
82
  'tool': {
75
83
  ...routes.reduce((acc, route) => {
76
84
  const metadata = route.metadata as Skill
85
+ let args = extractArgs(metadata?.args)
77
86
  acc[metadata.skill!] = {
78
87
  name: metadata.title || metadata.skill,
79
88
  description: metadata.summary || '',
80
- args: metadata.args || {},
89
+ args: args,
81
90
  async execute(args: Record<string, any>) {
82
91
  const res = await router.run({
83
92
  path: route.path,
@@ -117,4 +126,17 @@ export const createRouterAgentPluginFn = (opts?: {
117
126
 
118
127
  export const usePluginInput = (): PluginInput => {
119
128
  return useContextKey<PluginInput>('plugin-input')
129
+ }
130
+
131
+ /**
132
+ * 如果args是z.object类型,拆分第一个Object的属性,比如z.object({ name: z.string(), age: z.number() }),拆分成{name: z.string(), age: z.number()}
133
+ * 如果args是普通对象,直接返回
134
+ * @param args
135
+ * @returns
136
+ */
137
+ export const extractArgs = (args: any) => {
138
+ if (args && typeof args === 'object' && typeof args.shape === 'object') {
139
+ return args.shape
140
+ }
141
+ return args || {}
120
142
  }
package/src/route.ts CHANGED
@@ -97,6 +97,7 @@ export type Skill<T = SimpleObject> = {
97
97
  skill: string;
98
98
  title: string;
99
99
  summary?: string;
100
+ tags?: string[];
100
101
  args?: {
101
102
  [key: string]: any
102
103
  };
@@ -106,6 +107,12 @@ export const tool = {
106
107
  }
107
108
  /** */
108
109
  export const createSkill = <T = SimpleObject>(skill: Skill<T>): Skill<T> => {
110
+ if (skill.tags) {
111
+ const hasOpencode = skill.tags.includes('opencode');
112
+ if (!hasOpencode) {
113
+ skill.tags.push('opencode');
114
+ }
115
+ }
109
116
  return {
110
117
  args: {},
111
118
  ...skill
@@ -130,7 +137,6 @@ export class Route<U = { [key: string]: any }, T extends SimpleObject = SimpleOb
130
137
  metadata?: T;
131
138
  middleware?: RouteMiddleware[]; // middleware
132
139
  type? = 'route';
133
- data?: any;
134
140
  /**
135
141
  * 是否开启debug,开启后会打印错误信息
136
142
  */
@@ -234,19 +240,25 @@ export class Route<U = { [key: string]: any }, T extends SimpleObject = SimpleOb
234
240
  addTo(router: QueryRouter | { add: (route: Route) => void;[key: string]: any }, opts?: AddOpts) {
235
241
  router.add(this, opts);
236
242
  }
237
- setData(data: any) {
238
- this.data = data;
239
- return this;
240
- }
241
243
  throw(code?: number | string, message?: string, tips?: string): void;
242
244
  throw(...args: any[]) {
243
245
  throw new CustomError(...args);
244
246
  }
245
247
  }
248
+ export const extractArgs = (args: any) => {
249
+ if (args && typeof args === 'object' && typeof args.shape === 'object') {
250
+ return args.shape as z.ZodRawShape;
251
+ }
252
+ return args || {};
253
+ };
254
+
246
255
  export const toJSONSchema = (route: RouteInfo) => {
247
256
  const pickValues = pick(route, pickValue as any);
248
257
  if (pickValues?.metadata?.args) {
249
- const args = pickValues.metadata.args;
258
+ let args = pickValues.metadata.args;
259
+ // 如果 args 本身是一个 zod object schema,先提取 shape
260
+ args = extractArgs(args);
261
+
250
262
  const keys = Object.keys(args);
251
263
  const newArgs: { [key: string]: any } = {};
252
264
  for (let key of keys) {
@@ -265,6 +277,11 @@ export const toJSONSchema = (route: RouteInfo) => {
265
277
  export const fromJSONSchema = (route: RouteInfo): RouteInfo => {
266
278
  const args = route?.metadata?.args;
267
279
  if (!args) return route;
280
+ if (args["$schema"] || (args.type === 'object' && args.properties && typeof args.properties === 'object')) {
281
+ // 可能是整个schema
282
+ route.metadata.args = z.fromJSONSchema(args);
283
+ return route;
284
+ }
268
285
  const keys = Object.keys(args);
269
286
  const newArgs: { [key: string]: any } = {};
270
287
  for (let key of keys) {