@tankpkg/mcp-server 0.11.0 → 0.13.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.
package/dist/index.js CHANGED
@@ -15,6 +15,162 @@ const MANIFEST_FILENAME = "tank.json";
15
15
  const LEGACY_MANIFEST_FILENAME = "skills.json";
16
16
  const LOCKFILE_FILENAME = "tank.lock";
17
17
  const LEGACY_LOCKFILE_FILENAME = "skills.lock";
18
+ const supportLevelSchema$1 = z.enum([
19
+ "full",
20
+ "degraded",
21
+ "none"
22
+ ]);
23
+ const adapterCapabilitiesSchema$1 = z.object({
24
+ instruction: supportLevelSchema$1,
25
+ hook: supportLevelSchema$1,
26
+ tool: supportLevelSchema$1,
27
+ agent: supportLevelSchema$1,
28
+ rule: supportLevelSchema$1,
29
+ resource: supportLevelSchema$1,
30
+ prompt: supportLevelSchema$1
31
+ }).strict();
32
+ const compilationWarningSchema$1 = z.object({
33
+ level: z.enum(["degraded", "skipped"]),
34
+ atomKind: z.string(),
35
+ message: z.string()
36
+ }).strict();
37
+ const fileWriteSchema = z.object({
38
+ path: z.string().min(1),
39
+ content: z.string()
40
+ }).strict();
41
+ z.object({
42
+ files: z.array(fileWriteSchema),
43
+ warnings: z.array(compilationWarningSchema$1)
44
+ }).strict();
45
+ z.object({
46
+ name: z.string().min(1, "Adapter name must not be empty"),
47
+ supportedRange: z.string().min(1, "Supported range must not be empty"),
48
+ capabilities: adapterCapabilitiesSchema$1
49
+ }).strict();
50
+ z.enum([
51
+ "instruction",
52
+ "hook",
53
+ "tool",
54
+ "agent",
55
+ "rule",
56
+ "resource",
57
+ "prompt"
58
+ ]);
59
+ const extensionBagSchema$1 = z.record(z.string(), z.unknown()).optional();
60
+ const modelTierSchema$1 = z.enum([
61
+ "fast",
62
+ "balanced",
63
+ "powerful",
64
+ "custom"
65
+ ]);
66
+ modelTierSchema$1.options;
67
+ const canonicalToolNameSchema$1 = z.enum([
68
+ "bash",
69
+ "read",
70
+ "write",
71
+ "edit",
72
+ "grep",
73
+ "glob",
74
+ "lsp",
75
+ "mcp",
76
+ "browser",
77
+ "fetch",
78
+ "git",
79
+ "task",
80
+ "notebook"
81
+ ]);
82
+ canonicalToolNameSchema$1.options;
83
+ const agentIRSchema$1 = z.object({
84
+ kind: z.literal("agent"),
85
+ name: z.string().min(1, "Agent name must not be empty"),
86
+ role: z.string().min(1, "Agent role must not be empty"),
87
+ tools: z.array(canonicalToolNameSchema$1.or(z.string().min(1))).optional(),
88
+ model: modelTierSchema$1.or(z.string().min(1)).optional(),
89
+ readonly: z.boolean().optional(),
90
+ extensions: extensionBagSchema$1
91
+ }).strict();
92
+ const hookEventSchema$1 = z.enum([
93
+ "pre-tool-use",
94
+ "post-tool-use",
95
+ "pre-file-read",
96
+ "post-file-read",
97
+ "pre-file-write",
98
+ "post-file-write",
99
+ "file-edited",
100
+ "file-watcher-updated",
101
+ "pre-command",
102
+ "post-command",
103
+ "pre-mcp-tool-use",
104
+ "post-mcp-tool-use",
105
+ "session-created",
106
+ "session-updated",
107
+ "session-idle",
108
+ "session-error",
109
+ "session-deleted",
110
+ "pre-stop",
111
+ "task-start",
112
+ "task-resume",
113
+ "task-complete",
114
+ "task-cancel",
115
+ "pre-user-prompt",
116
+ "post-response",
117
+ "message-updated",
118
+ "message-removed",
119
+ "system-prompt-transform",
120
+ "pre-context-compact",
121
+ "post-context-compact",
122
+ "permission-asked",
123
+ "permission-replied",
124
+ "lsp-diagnostics",
125
+ "lsp-updated",
126
+ "subagent-start",
127
+ "subagent-complete",
128
+ "subagent-tool-use",
129
+ "shell-env",
130
+ "todo-updated",
131
+ "installation-updated"
132
+ ]);
133
+ hookEventSchema$1.options;
134
+ const hookActionIRSchema$1 = z.object({
135
+ action: z.enum([
136
+ "block",
137
+ "allow",
138
+ "rewrite",
139
+ "injectContext"
140
+ ]),
141
+ match: z.string().optional(),
142
+ reason: z.string().optional(),
143
+ value: z.string().optional()
144
+ }).strict();
145
+ const hookDslHandlerSchema = z.object({
146
+ type: z.literal("dsl"),
147
+ actions: z.array(hookActionIRSchema$1).min(1, "DSL handler must have at least one action")
148
+ }).strict();
149
+ const hookJsHandlerSchema = z.object({
150
+ type: z.literal("js"),
151
+ entry: z.string().min(1, "JS handler entry path must not be empty")
152
+ }).strict();
153
+ const hookHandlerIRSchema$1 = z.discriminatedUnion("type", [hookDslHandlerSchema, hookJsHandlerSchema]);
154
+ const hookIRSchema$1 = z.object({
155
+ kind: z.literal("hook"),
156
+ name: z.string().optional(),
157
+ event: hookEventSchema$1,
158
+ match: canonicalToolNameSchema$1.or(z.string().min(1)).optional(),
159
+ handler: hookHandlerIRSchema$1,
160
+ scope: z.enum(["project", "global"]).optional(),
161
+ extensions: extensionBagSchema$1
162
+ }).strict();
163
+ const instructionIRSchema$1 = z.object({
164
+ kind: z.literal("instruction"),
165
+ content: z.string().min(1, "Content path must not be empty"),
166
+ scope: z.enum([
167
+ "project",
168
+ "global",
169
+ "directory"
170
+ ]).optional(),
171
+ globs: z.array(z.string()).optional(),
172
+ extensions: extensionBagSchema$1
173
+ }).strict();
18
174
  const networkPermissionsSchema$1 = z.object({ outbound: z.array(z.string()).optional() }).strict();
19
175
  const filesystemPermissionsSchema$1 = z.object({
20
176
  read: z.array(z.string()).optional(),
@@ -53,7 +209,77 @@ z.enum([
53
209
  "org.member.remove",
54
210
  "org.delete"
55
211
  ]);
56
- const skillsJsonSchema = z.object({
212
+ const promptIRSchema$1 = z.object({
213
+ kind: z.literal("prompt"),
214
+ name: z.string().min(1, "Prompt name must not be empty"),
215
+ description: z.string().optional(),
216
+ template: z.string().min(1, "Prompt template path must not be empty"),
217
+ arguments: z.array(z.object({
218
+ name: z.string(),
219
+ description: z.string().optional(),
220
+ required: z.boolean().optional()
221
+ }).strict()).optional(),
222
+ extensions: extensionBagSchema$1
223
+ }).strict();
224
+ const resourceIRSchema$1 = z.object({
225
+ kind: z.literal("resource"),
226
+ name: z.string().optional(),
227
+ uri: z.string().min(1, "Resource URI must not be empty"),
228
+ description: z.string().optional(),
229
+ mimeType: z.string().optional(),
230
+ extensions: extensionBagSchema$1
231
+ }).strict();
232
+ const ruleIRSchema$1 = z.object({
233
+ kind: z.literal("rule"),
234
+ name: z.string().optional(),
235
+ event: hookEventSchema$1,
236
+ match: canonicalToolNameSchema$1.or(z.string().min(1)).optional(),
237
+ policy: z.enum([
238
+ "block",
239
+ "allow",
240
+ "warn"
241
+ ]),
242
+ reason: z.string().optional(),
243
+ extensions: extensionBagSchema$1
244
+ }).strict();
245
+ const mcpServerConfigSchema$1 = z.object({
246
+ command: z.string().min(1).optional(),
247
+ args: z.array(z.string()).optional(),
248
+ env: z.record(z.string(), z.string()).optional(),
249
+ runtime: z.string().min(1).optional(),
250
+ entry: z.string().min(1).optional()
251
+ }).strict().refine((data) => data.command || data.runtime && data.entry, "MCP config must have either \"command\" or both \"runtime\" and \"entry\"");
252
+ const toolIRSchema$1 = z.object({
253
+ kind: z.literal("tool"),
254
+ name: z.string().min(1, "Tool name must not be empty"),
255
+ description: z.string().optional(),
256
+ mcp: mcpServerConfigSchema$1.optional(),
257
+ extensions: extensionBagSchema$1
258
+ }).strict();
259
+ const NAME_PATTERN$1 = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
260
+ const SEMVER_PATTERN$2 = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
261
+ const atomIRSchema$1 = z.discriminatedUnion("kind", [
262
+ instructionIRSchema$1,
263
+ hookIRSchema$1,
264
+ toolIRSchema$1,
265
+ agentIRSchema$1,
266
+ ruleIRSchema$1,
267
+ resourceIRSchema$1,
268
+ promptIRSchema$1
269
+ ]);
270
+ z.object({
271
+ name: z.string().min(1, "Name must not be empty").max(214, `Name must be 214 characters or fewer`).regex(NAME_PATTERN$1, "Name must be scoped (@org/name), lowercase alphanumeric and hyphens"),
272
+ version: z.string().regex(SEMVER_PATTERN$2, "Version must be valid semver"),
273
+ description: z.string().max(500).optional(),
274
+ atoms: z.array(atomIRSchema$1),
275
+ includes: z.array(z.string()).optional(),
276
+ skills: z.record(z.string(), z.string()).optional(),
277
+ permissions: permissionsSchema$1.optional(),
278
+ repository: z.string().url("Repository must be a valid URL").optional(),
279
+ visibility: z.enum(["public", "private"]).optional(),
280
+ audit: z.object({ min_score: z.number().min(0).max(10) }).strict().optional()
281
+ }).strict();
282
+ const baseManifestFields$1 = {
57
283
  name: z.string().min(1, "Name must not be empty").max(214, `Name must be 214 characters or fewer`).regex(/^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/, "Name must be scoped (@org/name), lowercase alphanumeric and hyphens"),
58
284
  version: z.string().regex(/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/, "Version must be valid semver"),
59
285
  description: z.string().max(500, `Description must be 500 characters or fewer`).optional(),
@@ -62,7 +288,30 @@ const skillsJsonSchema = z.object({
62
288
  repository: z.string().url("Repository must be a valid URL").optional(),
63
289
  visibility: z.enum(["public", "private"]).optional(),
64
290
  audit: z.object({ min_score: z.number().min(0).max(10) }).strict().optional()
291
+ };
292
+ /** Legacy skills.json schema — strict, no atoms. Used for backward-compatible consumers. */
293
+ const skillsJsonSchema = z.object(baseManifestFields$1).strict();
294
+ z.object({
295
+ ...baseManifestFields$1,
296
+ atoms: z.array(z.record(z.string(), z.unknown())).optional(),
297
+ includes: z.array(z.string()).optional()
65
298
  }).strict();
299
+ const SKILL_SOURCES$1 = [
300
+ "registry",
301
+ "github",
302
+ "clawhub",
303
+ "skills_sh",
304
+ "agentskills_il",
305
+ "npm",
306
+ "local"
307
+ ];
308
+ const SCAN_VERDICTS$1 = [
309
+ "pass",
310
+ "pass_with_notes",
311
+ "flagged",
312
+ "fail",
313
+ "error"
314
+ ];
66
315
  const lockedSkillV1Schema$1 = z.object({
67
316
  resolved: z.string().url(),
68
317
  integrity: z.string().regex(/^sha512-/, "Integrity must start with sha512-"),
@@ -78,7 +327,10 @@ const lockedSkillSchema$1 = z.object({
78
327
  integrity: z.string().regex(/^sha512-/, "Integrity must start with sha512-"),
79
328
  permissions: permissionsSchema$1,
80
329
  audit_score: z.number().min(0).max(10).nullable(),
81
- dependencies: z.record(z.string(), z.string()).optional()
330
+ dependencies: z.record(z.string(), z.string()).optional(),
331
+ source: z.enum(SKILL_SOURCES$1).optional(),
332
+ scan_verdict: z.enum(SCAN_VERDICTS$1).optional(),
333
+ scanned_at: z.string().optional()
82
334
  });
83
335
  z.object({
84
336
  lockfileVersion: z.union([z.literal(1), z.literal(2)]),
@@ -1737,6 +1989,61 @@ const $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
1737
1989
  });
1738
1990
  };
1739
1991
  });
1992
+ const $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnion", (inst, def) => {
1993
+ def.inclusive = false;
1994
+ $ZodUnion.init(inst, def);
1995
+ const _super = inst._zod.parse;
1996
+ defineLazy(inst._zod, "propValues", () => {
1997
+ const propValues = {};
1998
+ for (const option of def.options) {
1999
+ const pv = option._zod.propValues;
2000
+ if (!pv || Object.keys(pv).length === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
2001
+ for (const [k, v] of Object.entries(pv)) {
2002
+ if (!propValues[k]) propValues[k] = /* @__PURE__ */ new Set();
2003
+ for (const val of v) propValues[k].add(val);
2004
+ }
2005
+ }
2006
+ return propValues;
2007
+ });
2008
+ const disc = cached(() => {
2009
+ const opts = def.options;
2010
+ const map = /* @__PURE__ */ new Map();
2011
+ for (const o of opts) {
2012
+ const values = o._zod.propValues?.[def.discriminator];
2013
+ if (!values || values.size === 0) throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
2014
+ for (const v of values) {
2015
+ if (map.has(v)) throw new Error(`Duplicate discriminator value "${String(v)}"`);
2016
+ map.set(v, o);
2017
+ }
2018
+ }
2019
+ return map;
2020
+ });
2021
+ inst._zod.parse = (payload, ctx) => {
2022
+ const input = payload.value;
2023
+ if (!isObject(input)) {
2024
+ payload.issues.push({
2025
+ code: "invalid_type",
2026
+ expected: "object",
2027
+ input,
2028
+ inst
2029
+ });
2030
+ return payload;
2031
+ }
2032
+ const opt = disc.value.get(input?.[def.discriminator]);
2033
+ if (opt) return opt._zod.run(payload, ctx);
2034
+ if (def.unionFallback) return _super(payload, ctx);
2035
+ payload.issues.push({
2036
+ code: "invalid_union",
2037
+ errors: [],
2038
+ note: "No matching discriminator",
2039
+ discriminator: def.discriminator,
2040
+ input,
2041
+ path: [def.discriminator],
2042
+ inst
2043
+ });
2044
+ return payload;
2045
+ };
2046
+ });
1740
2047
  const $ZodIntersection = /* @__PURE__ */ $constructor("$ZodIntersection", (inst, def) => {
1741
2048
  $ZodType.init(inst, def);
1742
2049
  inst._zod.parse = (payload, ctx) => {
@@ -3685,6 +3992,18 @@ function union(options, params) {
3685
3992
  ...normalizeParams(params)
3686
3993
  });
3687
3994
  }
3995
+ const ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("ZodDiscriminatedUnion", (inst, def) => {
3996
+ ZodUnion.init(inst, def);
3997
+ $ZodDiscriminatedUnion.init(inst, def);
3998
+ });
3999
+ function discriminatedUnion(discriminator, options, params) {
4000
+ return new ZodDiscriminatedUnion({
4001
+ type: "union",
4002
+ options,
4003
+ discriminator,
4004
+ ...normalizeParams(params)
4005
+ });
4006
+ }
3688
4007
  const ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
3689
4008
  $ZodIntersection.init(inst, def);
3690
4009
  ZodType.init(inst, def);
@@ -3930,6 +4249,159 @@ function superRefine(fn) {
3930
4249
  return /* @__PURE__ */ _superRefine(fn);
3931
4250
  }
3932
4251
  const REGISTRY_URL = process.env.TANK_REGISTRY_URL || "https://www.tankpkg.dev";
4252
+ const supportLevelSchema = _enum([
4253
+ "full",
4254
+ "degraded",
4255
+ "none"
4256
+ ]);
4257
+ const adapterCapabilitiesSchema = object({
4258
+ instruction: supportLevelSchema,
4259
+ hook: supportLevelSchema,
4260
+ tool: supportLevelSchema,
4261
+ agent: supportLevelSchema,
4262
+ rule: supportLevelSchema,
4263
+ resource: supportLevelSchema,
4264
+ prompt: supportLevelSchema
4265
+ }).strict();
4266
+ const compilationWarningSchema = object({
4267
+ level: _enum(["degraded", "skipped"]),
4268
+ atomKind: string(),
4269
+ message: string()
4270
+ }).strict();
4271
+ object({
4272
+ files: array(object({
4273
+ path: string().min(1),
4274
+ content: string()
4275
+ }).strict()),
4276
+ warnings: array(compilationWarningSchema)
4277
+ }).strict();
4278
+ object({
4279
+ name: string().min(1, "Adapter name must not be empty"),
4280
+ supportedRange: string().min(1, "Supported range must not be empty"),
4281
+ capabilities: adapterCapabilitiesSchema
4282
+ }).strict();
4283
+ _enum([
4284
+ "instruction",
4285
+ "hook",
4286
+ "tool",
4287
+ "agent",
4288
+ "rule",
4289
+ "resource",
4290
+ "prompt"
4291
+ ]);
4292
+ const extensionBagSchema = record(string(), unknown()).optional();
4293
+ const modelTierSchema = _enum([
4294
+ "fast",
4295
+ "balanced",
4296
+ "powerful",
4297
+ "custom"
4298
+ ]);
4299
+ modelTierSchema.options;
4300
+ const canonicalToolNameSchema = _enum([
4301
+ "bash",
4302
+ "read",
4303
+ "write",
4304
+ "edit",
4305
+ "grep",
4306
+ "glob",
4307
+ "lsp",
4308
+ "mcp",
4309
+ "browser",
4310
+ "fetch",
4311
+ "git",
4312
+ "task",
4313
+ "notebook"
4314
+ ]);
4315
+ canonicalToolNameSchema.options;
4316
+ const agentIRSchema = object({
4317
+ kind: literal("agent"),
4318
+ name: string().min(1, "Agent name must not be empty"),
4319
+ role: string().min(1, "Agent role must not be empty"),
4320
+ tools: array(canonicalToolNameSchema.or(string().min(1))).optional(),
4321
+ model: modelTierSchema.or(string().min(1)).optional(),
4322
+ readonly: boolean().optional(),
4323
+ extensions: extensionBagSchema
4324
+ }).strict();
4325
+ const hookEventSchema = _enum([
4326
+ "pre-tool-use",
4327
+ "post-tool-use",
4328
+ "pre-file-read",
4329
+ "post-file-read",
4330
+ "pre-file-write",
4331
+ "post-file-write",
4332
+ "file-edited",
4333
+ "file-watcher-updated",
4334
+ "pre-command",
4335
+ "post-command",
4336
+ "pre-mcp-tool-use",
4337
+ "post-mcp-tool-use",
4338
+ "session-created",
4339
+ "session-updated",
4340
+ "session-idle",
4341
+ "session-error",
4342
+ "session-deleted",
4343
+ "pre-stop",
4344
+ "task-start",
4345
+ "task-resume",
4346
+ "task-complete",
4347
+ "task-cancel",
4348
+ "pre-user-prompt",
4349
+ "post-response",
4350
+ "message-updated",
4351
+ "message-removed",
4352
+ "system-prompt-transform",
4353
+ "pre-context-compact",
4354
+ "post-context-compact",
4355
+ "permission-asked",
4356
+ "permission-replied",
4357
+ "lsp-diagnostics",
4358
+ "lsp-updated",
4359
+ "subagent-start",
4360
+ "subagent-complete",
4361
+ "subagent-tool-use",
4362
+ "shell-env",
4363
+ "todo-updated",
4364
+ "installation-updated"
4365
+ ]);
4366
+ hookEventSchema.options;
4367
+ const hookActionIRSchema = object({
4368
+ action: _enum([
4369
+ "block",
4370
+ "allow",
4371
+ "rewrite",
4372
+ "injectContext"
4373
+ ]),
4374
+ match: string().optional(),
4375
+ reason: string().optional(),
4376
+ value: string().optional()
4377
+ }).strict();
4378
+ const hookHandlerIRSchema = discriminatedUnion("type", [object({
4379
+ type: literal("dsl"),
4380
+ actions: array(hookActionIRSchema).min(1, "DSL handler must have at least one action")
4381
+ }).strict(), object({
4382
+ type: literal("js"),
4383
+ entry: string().min(1, "JS handler entry path must not be empty")
4384
+ }).strict()]);
4385
+ const hookIRSchema = object({
4386
+ kind: literal("hook"),
4387
+ name: string().optional(),
4388
+ event: hookEventSchema,
4389
+ match: canonicalToolNameSchema.or(string().min(1)).optional(),
4390
+ handler: hookHandlerIRSchema,
4391
+ scope: _enum(["project", "global"]).optional(),
4392
+ extensions: extensionBagSchema
4393
+ }).strict();
4394
+ const instructionIRSchema = object({
4395
+ kind: literal("instruction"),
4396
+ content: string().min(1, "Content path must not be empty"),
4397
+ scope: _enum([
4398
+ "project",
4399
+ "global",
4400
+ "directory"
4401
+ ]).optional(),
4402
+ globs: array(string()).optional(),
4403
+ extensions: extensionBagSchema
4404
+ }).strict();
3933
4405
  const networkPermissionsSchema = object({ outbound: array(string()).optional() }).strict();
3934
4406
  const filesystemPermissionsSchema = object({
3935
4407
  read: array(string()).optional(),
@@ -3968,7 +4440,77 @@ _enum([
3968
4440
  "org.member.remove",
3969
4441
  "org.delete"
3970
4442
  ]);
4443
+ const promptIRSchema = object({
4444
+ kind: literal("prompt"),
4445
+ name: string().min(1, "Prompt name must not be empty"),
4446
+ description: string().optional(),
4447
+ template: string().min(1, "Prompt template path must not be empty"),
4448
+ arguments: array(object({
4449
+ name: string(),
4450
+ description: string().optional(),
4451
+ required: boolean().optional()
4452
+ }).strict()).optional(),
4453
+ extensions: extensionBagSchema
4454
+ }).strict();
4455
+ const resourceIRSchema = object({
4456
+ kind: literal("resource"),
4457
+ name: string().optional(),
4458
+ uri: string().min(1, "Resource URI must not be empty"),
4459
+ description: string().optional(),
4460
+ mimeType: string().optional(),
4461
+ extensions: extensionBagSchema
4462
+ }).strict();
4463
+ const ruleIRSchema = object({
4464
+ kind: literal("rule"),
4465
+ name: string().optional(),
4466
+ event: hookEventSchema,
4467
+ match: canonicalToolNameSchema.or(string().min(1)).optional(),
4468
+ policy: _enum([
4469
+ "block",
4470
+ "allow",
4471
+ "warn"
4472
+ ]),
4473
+ reason: string().optional(),
4474
+ extensions: extensionBagSchema
4475
+ }).strict();
4476
+ const mcpServerConfigSchema = object({
4477
+ command: string().min(1).optional(),
4478
+ args: array(string()).optional(),
4479
+ env: record(string(), string()).optional(),
4480
+ runtime: string().min(1).optional(),
4481
+ entry: string().min(1).optional()
4482
+ }).strict().refine((data) => data.command || data.runtime && data.entry, "MCP config must have either \"command\" or both \"runtime\" and \"entry\"");
4483
+ const toolIRSchema = object({
4484
+ kind: literal("tool"),
4485
+ name: string().min(1, "Tool name must not be empty"),
4486
+ description: string().optional(),
4487
+ mcp: mcpServerConfigSchema.optional(),
4488
+ extensions: extensionBagSchema
4489
+ }).strict();
4490
+ const NAME_PATTERN = /^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/;
4491
+ const SEMVER_PATTERN$1 = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
4492
+ const atomIRSchema = discriminatedUnion("kind", [
4493
+ instructionIRSchema,
4494
+ hookIRSchema,
4495
+ toolIRSchema,
4496
+ agentIRSchema,
4497
+ ruleIRSchema,
4498
+ resourceIRSchema,
4499
+ promptIRSchema
4500
+ ]);
3971
4501
  object({
4502
+ name: string().min(1, "Name must not be empty").max(214, `Name must be 214 characters or fewer`).regex(NAME_PATTERN, "Name must be scoped (@org/name), lowercase alphanumeric and hyphens"),
4503
+ version: string().regex(SEMVER_PATTERN$1, "Version must be valid semver"),
4504
+ description: string().max(500).optional(),
4505
+ atoms: array(atomIRSchema),
4506
+ includes: array(string()).optional(),
4507
+ skills: record(string(), string()).optional(),
4508
+ permissions: permissionsSchema.optional(),
4509
+ repository: string().url("Repository must be a valid URL").optional(),
4510
+ visibility: _enum(["public", "private"]).optional(),
4511
+ audit: object({ min_score: number().min(0).max(10) }).strict().optional()
4512
+ }).strict();
4513
+ const baseManifestFields = {
3972
4514
  name: string().min(1, "Name must not be empty").max(214, `Name must be 214 characters or fewer`).regex(/^@[a-z0-9-]+\/[a-z0-9][a-z0-9-]*$/, "Name must be scoped (@org/name), lowercase alphanumeric and hyphens"),
3973
4515
  version: string().regex(/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/, "Version must be valid semver"),
3974
4516
  description: string().max(500, `Description must be 500 characters or fewer`).optional(),
@@ -3977,7 +4519,29 @@ object({
3977
4519
  repository: string().url("Repository must be a valid URL").optional(),
3978
4520
  visibility: _enum(["public", "private"]).optional(),
3979
4521
  audit: object({ min_score: number().min(0).max(10) }).strict().optional()
4522
+ };
4523
+ object(baseManifestFields).strict();
4524
+ object({
4525
+ ...baseManifestFields,
4526
+ atoms: array(record(string(), unknown())).optional(),
4527
+ includes: array(string()).optional()
3980
4528
  }).strict();
4529
+ const SKILL_SOURCES = [
4530
+ "registry",
4531
+ "github",
4532
+ "clawhub",
4533
+ "skills_sh",
4534
+ "agentskills_il",
4535
+ "npm",
4536
+ "local"
4537
+ ];
4538
+ const SCAN_VERDICTS = [
4539
+ "pass",
4540
+ "pass_with_notes",
4541
+ "flagged",
4542
+ "fail",
4543
+ "error"
4544
+ ];
3981
4545
  const lockedSkillV1Schema = object({
3982
4546
  resolved: string().url(),
3983
4547
  integrity: string().regex(/^sha512-/, "Integrity must start with sha512-"),
@@ -3993,7 +4557,10 @@ const lockedSkillSchema = object({
3993
4557
  integrity: string().regex(/^sha512-/, "Integrity must start with sha512-"),
3994
4558
  permissions: permissionsSchema,
3995
4559
  audit_score: number().min(0).max(10).nullable(),
3996
- dependencies: record(string(), string()).optional()
4560
+ dependencies: record(string(), string()).optional(),
4561
+ source: _enum(SKILL_SOURCES).optional(),
4562
+ scan_verdict: _enum(SCAN_VERDICTS).optional(),
4563
+ scanned_at: string().optional()
3997
4564
  });
3998
4565
  object({
3999
4566
  lockfileVersion: union([literal(1), literal(2)]),