@hasna/skills 0.1.54 → 0.1.55

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/bin/index.js CHANGED
@@ -36860,7 +36860,7 @@ var package_default;
36860
36860
  var init_package = __esm(() => {
36861
36861
  package_default = {
36862
36862
  name: "@hasna/skills",
36863
- version: "0.1.54",
36863
+ version: "0.1.55",
36864
36864
  description: "Skills library for AI coding agents",
36865
36865
  type: "module",
36866
36866
  bin: {
@@ -38067,9 +38067,9 @@ function getSkillRunPricing(slug, input, args = []) {
38067
38067
  tier: "premium",
38068
38068
  costCents: ARTICLE_USER_COST_CENTS * count,
38069
38069
  costMicros: ARTICLE_INTERNAL_COST_CENTS * count * 1e4,
38070
- provider: "cerebras",
38071
- model: "gpt-oss",
38072
- providers: ["cerebras"],
38070
+ provider: "openrouter",
38071
+ model: "openai/gpt-4o-mini",
38072
+ providers: ["openrouter"],
38073
38073
  description: `Remote article generation; ${count} article${count === 1 ? "" : "s"}`
38074
38074
  };
38075
38075
  }
@@ -38437,8 +38437,8 @@ var init_pricing = __esm(() => {
38437
38437
  { slug: "transcript", displayName: "Transcript", tier: "premium", costCents: 10, providers: ["openai", "elevenlabs", "deepgram", "hosted"], description: "Audio/video transcription with timestamps, diarization, and URL support" },
38438
38438
  { slug: "webcrawling", displayName: "Web Crawling", tier: "premium", costCents: 5, providers: ["firecrawl"], description: "Structured web page crawling and extraction" },
38439
38439
  { slug: "browse", displayName: "Browse", tier: "premium", costCents: 5, providers: ["browser"], description: "Web browsing and page interaction" },
38440
- { slug: "read-pdf", displayName: "Read PDF", tier: "premium", costCents: 5, providers: ["cerebras"], description: "Hosted PDF extraction and structured content analysis" },
38441
- { slug: "pdf-read", displayName: "PDF Read", tier: "premium", costCents: 5, providers: ["cerebras"], description: "Hosted multi-PDF text extraction with page ranges" },
38440
+ { slug: "read-pdf", displayName: "Read PDF", tier: "premium", costCents: 5, providers: ["openrouter"], description: "Hosted PDF extraction and structured content analysis" },
38441
+ { slug: "pdf-read", displayName: "PDF Read", tier: "premium", costCents: 5, providers: ["openrouter"], description: "Hosted multi-PDF text extraction with page ranges" },
38442
38442
  { slug: "pdf-to-markdown", displayName: "PDF to Markdown", tier: "premium", costCents: 5, providers: ["hosted"], description: "Hosted PDF to markdown conversion and cleanup" },
38443
38443
  { slug: "pdf-to-dataset", displayName: "PDF to Dataset", tier: "premium", costCents: 15, providers: ["hosted"], description: "Hosted PDF table and form extraction into CSV/JSON datasets" },
38444
38444
  { slug: "market-research-report", displayName: "Market Research Report", tier: "premium", costCents: 150, providers: ["hosted"], description: "Hosted market research report with competitor, audience, pricing, and source artifacts" },
@@ -40153,6 +40153,13 @@ var init_project_management = __esm(() => {
40153
40153
  description: "Create, validate, and serve standardized Hasna project dashboard reports",
40154
40154
  category: "Project Management",
40155
40155
  tags: ["projects", "dashboard", "reports", "json-render"]
40156
+ },
40157
+ {
40158
+ name: "todos-plan",
40159
+ displayName: "Todos Plan",
40160
+ description: "Author, sync, route, and verify Todos plans using Todos CLI plan IDs as source of truth",
40161
+ category: "Project Management",
40162
+ tags: ["todos", "plans", "tasks", "verification", "workflow"]
40156
40163
  }
40157
40164
  ];
40158
40165
  });
@@ -40530,14 +40537,14 @@ var init_data_analysis = __esm(() => {
40530
40537
  displayName: "Read PDF",
40531
40538
  description: "Extract text and structured content from PDF files with chunked Claude document analysis",
40532
40539
  category: "Data & Analysis",
40533
- tags: ["pdf", "documents", "extraction", "analysis", "remote", "premium", "cerebras"]
40540
+ tags: ["pdf", "documents", "extraction", "analysis", "remote", "premium", "gateway"]
40534
40541
  },
40535
40542
  {
40536
40543
  name: "pdf-read",
40537
40544
  displayName: "PDF Read",
40538
40545
  description: "Read multiple PDFs with page-range selection, chunked reading, and parallel processing",
40539
40546
  category: "Data & Analysis",
40540
- tags: ["pdf", "reader", "extraction", "parallel", "remote", "premium", "cerebras"]
40547
+ tags: ["pdf", "reader", "extraction", "parallel", "remote", "premium", "gateway"]
40541
40548
  },
40542
40549
  {
40543
40550
  name: "pdf-to-markdown",
@@ -43770,6 +43777,7 @@ var init_discovery = __esm(() => {
43770
43777
  "DALL-E 3",
43771
43778
  "GPT-4o Mini",
43772
43779
  "Cerebras",
43780
+ "OpenRouter",
43773
43781
  "Firecrawl",
43774
43782
  "ElevenLabs",
43775
43783
  "Anthropic",
@@ -43798,6 +43806,7 @@ var init_discovery = __esm(() => {
43798
43806
  "google",
43799
43807
  "minimax",
43800
43808
  "openai",
43809
+ "openrouter",
43801
43810
  "seedance",
43802
43811
  "whisper",
43803
43812
  "xai"
@@ -43811,6 +43820,7 @@ var init_discovery = __esm(() => {
43811
43820
  "GOOGLE_",
43812
43821
  "MINIMAX_",
43813
43822
  "OPENAI_",
43823
+ "OPENROUTER_",
43814
43824
  "XAI_"
43815
43825
  ];
43816
43826
  VENDOR_PACKAGE_PATTERNS = [
@@ -43821,6 +43831,7 @@ var init_discovery = __esm(() => {
43821
43831
  /gemini/i,
43822
43832
  /minimax/i,
43823
43833
  /openai/i,
43834
+ /openrouter/i,
43824
43835
  /xai/i
43825
43836
  ];
43826
43837
  vendorPattern = new RegExp(`\\b(${VENDOR_TERMS.map(escapeRegExp2).join("|")})\\b`, "gi");
@@ -59224,6 +59235,484 @@ var init_introspect = __esm(() => {
59224
59235
  init_discovery();
59225
59236
  });
59226
59237
 
59238
+ // src/lib/tool-primitives.ts
59239
+ function listToolPrimitives(query) {
59240
+ const needle = query?.trim().toLowerCase();
59241
+ return TOOL_PRIMITIVES.filter((primitive) => !needle || primitiveHaystack(primitive).includes(needle)).map(summarizeToolPrimitive).sort((a, b) => a.name.localeCompare(b.name));
59242
+ }
59243
+ function getToolPrimitive(name) {
59244
+ return clone3(primitiveByName.get(name));
59245
+ }
59246
+ function getSkillToolDependencies(name) {
59247
+ const skill = getSkill(name);
59248
+ if (!skill)
59249
+ return null;
59250
+ return createSkillToolDependencies(skill);
59251
+ }
59252
+ function createSkillToolDependencies(skill) {
59253
+ const dependencies = inferPrimitiveDependencies(skill);
59254
+ const primitiveNames = new Set(dependencies.map((dependency) => dependency.primitive));
59255
+ return {
59256
+ schemaVersion: TOOL_PRIMITIVE_SCHEMA_VERSION,
59257
+ skill: skill.name,
59258
+ category: skill.category,
59259
+ source: skill.source ?? "official",
59260
+ dependencies,
59261
+ gatewayBacked: [...primitiveNames].some((name) => primitiveByName.get(name)?.runtime === "gateway" || name === "ai-gateway"),
59262
+ hostedRuntime: isHostedRuntimeSkill(skill) || primitiveNames.has("hosted-auth")
59263
+ };
59264
+ }
59265
+ function validateToolPrimitiveCoverage(profile = "all") {
59266
+ const skills = loadRegistryProfile(profile);
59267
+ const issues = [];
59268
+ let mappedSkillCount = 0;
59269
+ let gatewayBackedSkillCount = 0;
59270
+ let hostedRuntimeSkillCount = 0;
59271
+ for (const skill of skills) {
59272
+ const deps = createSkillToolDependencies(skill);
59273
+ if (deps.dependencies.length === 0) {
59274
+ issues.push({
59275
+ skill: skill.name,
59276
+ code: "skill.unmapped",
59277
+ message: `Skill '${skill.name}' has no primitive dependencies.`
59278
+ });
59279
+ continue;
59280
+ }
59281
+ mappedSkillCount++;
59282
+ if (deps.gatewayBacked)
59283
+ gatewayBackedSkillCount++;
59284
+ if (deps.hostedRuntime)
59285
+ hostedRuntimeSkillCount++;
59286
+ for (const dependency of deps.dependencies) {
59287
+ if (!primitiveByName.has(dependency.primitive)) {
59288
+ issues.push({
59289
+ skill: skill.name,
59290
+ code: "primitive.missing",
59291
+ message: `Skill '${skill.name}' references missing primitive '${dependency.primitive}'.`
59292
+ });
59293
+ }
59294
+ }
59295
+ }
59296
+ return {
59297
+ schemaVersion: TOOL_PRIMITIVE_SCHEMA_VERSION,
59298
+ valid: issues.length === 0,
59299
+ profile,
59300
+ skillCount: skills.length,
59301
+ primitiveCount: TOOL_PRIMITIVES.length,
59302
+ mappedSkillCount,
59303
+ gatewayBackedSkillCount,
59304
+ hostedRuntimeSkillCount,
59305
+ issues
59306
+ };
59307
+ }
59308
+ function inferPrimitiveDependencies(skill) {
59309
+ const matches2 = [];
59310
+ const allRules = [...CATEGORY_RULES, ...NAME_RULES, ...KEYWORD_RULES];
59311
+ for (const rule of allRules) {
59312
+ if (!ruleMatches(skill, rule))
59313
+ continue;
59314
+ const primitive = primitiveByName.get(rule.primitive);
59315
+ if (!primitive)
59316
+ continue;
59317
+ matches2.push({
59318
+ skill: skill.name,
59319
+ primitive: primitive.name,
59320
+ family: primitive.family,
59321
+ required: rule.required ?? true,
59322
+ reason: rule.reason
59323
+ });
59324
+ }
59325
+ if (isHostedRuntimeSkill(skill)) {
59326
+ const primitive = primitiveByName.get("hosted-auth");
59327
+ matches2.push({
59328
+ skill: skill.name,
59329
+ primitive: primitive.name,
59330
+ family: primitive.family,
59331
+ required: true,
59332
+ reason: "Skill is premium, remote, or hosted and must use Skills account authentication."
59333
+ });
59334
+ }
59335
+ if (matches2.length === 0) {
59336
+ const primitive = primitiveByName.get("project-artifacts");
59337
+ matches2.push({
59338
+ skill: skill.name,
59339
+ primitive: primitive.name,
59340
+ family: primitive.family,
59341
+ required: true,
59342
+ reason: "Default workspace primitive for local skill execution, run logs, and artifacts."
59343
+ });
59344
+ }
59345
+ return dedupeDependencies(matches2).sort((a, b) => a.primitive.localeCompare(b.primitive));
59346
+ }
59347
+ function ruleMatches(skill, rule) {
59348
+ const name = skill.name.toLowerCase();
59349
+ const category = skill.category.toLowerCase();
59350
+ const tags = skill.tags.map((tag) => tag.toLowerCase());
59351
+ const haystack = [
59352
+ skill.name,
59353
+ skill.displayName,
59354
+ skill.description,
59355
+ skill.category,
59356
+ ...skill.tags
59357
+ ].join(" ").toLowerCase();
59358
+ if (rule.names?.some((candidate) => candidate.toLowerCase() === name))
59359
+ return true;
59360
+ if (rule.categories?.some((candidate) => candidate.toLowerCase() === category))
59361
+ return true;
59362
+ if (rule.tags?.some((candidate) => tags.includes(candidate.toLowerCase())))
59363
+ return true;
59364
+ if (rule.keywords?.some((keyword) => haystack.includes(keyword.toLowerCase())))
59365
+ return true;
59366
+ return false;
59367
+ }
59368
+ function isHostedRuntimeSkill(skill) {
59369
+ const tags = new Set(skill.tags.map((tag) => tag.toLowerCase()));
59370
+ return isPremiumSkill(skill.name) || HOSTED_RUNTIME_SKILL_NAMES.has(skill.name) || tags.has("premium") || tags.has("remote") || tags.has("hosted") || skill.pricing?.tier === "premium";
59371
+ }
59372
+ function dedupeDependencies(dependencies) {
59373
+ const byPrimitive = new Map;
59374
+ for (const dependency of dependencies) {
59375
+ const existing = byPrimitive.get(dependency.primitive);
59376
+ if (!existing) {
59377
+ byPrimitive.set(dependency.primitive, dependency);
59378
+ continue;
59379
+ }
59380
+ byPrimitive.set(dependency.primitive, {
59381
+ ...existing,
59382
+ required: existing.required || dependency.required,
59383
+ reason: existing.reason === dependency.reason ? existing.reason : `${existing.reason} ${dependency.reason}`
59384
+ });
59385
+ }
59386
+ return [...byPrimitive.values()];
59387
+ }
59388
+ function summarizeToolPrimitive(primitive) {
59389
+ return {
59390
+ name: primitive.name,
59391
+ title: primitive.title,
59392
+ family: primitive.family,
59393
+ runtime: primitive.runtime,
59394
+ description: primitive.description
59395
+ };
59396
+ }
59397
+ function primitiveHaystack(primitive) {
59398
+ return [
59399
+ primitive.name,
59400
+ primitive.title,
59401
+ primitive.family,
59402
+ primitive.description,
59403
+ primitive.runtime,
59404
+ ...primitive.capabilities
59405
+ ].join(" ").toLowerCase();
59406
+ }
59407
+ function clone3(value) {
59408
+ return value === undefined ? undefined : JSON.parse(JSON.stringify(value));
59409
+ }
59410
+ var TOOL_PRIMITIVE_SCHEMA_VERSION = 1, TOOL_PRIMITIVES, CATEGORY_RULES, NAME_RULES, KEYWORD_RULES, primitiveByName, HOSTED_RUNTIME_SKILL_NAMES;
59411
+ var init_tool_primitives = __esm(() => {
59412
+ init_registry();
59413
+ init_pricing();
59414
+ TOOL_PRIMITIVES = [
59415
+ {
59416
+ name: "ai-gateway",
59417
+ title: "AI Gateway",
59418
+ family: "ai",
59419
+ description: "Provider-neutral text, code, reasoning, and multimodal model calls routed through the configured hosted gateway.",
59420
+ runtime: "gateway",
59421
+ stable: true,
59422
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59423
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59424
+ apiSurfaces: ["runSkill", "SkillRunRecord", "RemoteSkillRunContract"],
59425
+ envVars: ["SKILLS_API_KEY"],
59426
+ outputTypes: ["text", "json", "markdown", "artifact"],
59427
+ capabilities: ["completion", "reasoning", "tool-calling", "vision-input", "structured-output"]
59428
+ },
59429
+ {
59430
+ name: "documents-read",
59431
+ title: "Document Read",
59432
+ family: "documents",
59433
+ description: "Read, parse, normalize, and extract from PDF, DOCX, slides, invoices, contracts, and other document files.",
59434
+ runtime: "mixed",
59435
+ stable: true,
59436
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59437
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59438
+ apiSurfaces: ["getSkillRequirements", "runSkill"],
59439
+ envVars: [],
59440
+ outputTypes: ["text", "json", "markdown"],
59441
+ capabilities: ["pdf-parse", "office-parse", "ocr", "metadata-extraction"]
59442
+ },
59443
+ {
59444
+ name: "documents-write",
59445
+ title: "Document Write",
59446
+ family: "documents",
59447
+ description: "Generate PDFs, DOCX, slide decks, ebooks, reports, and other downloadable document artifacts.",
59448
+ runtime: "mixed",
59449
+ stable: true,
59450
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59451
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59452
+ apiSurfaces: ["createSkillRun", "completeSkillRun", "writeRunLogs"],
59453
+ envVars: [],
59454
+ outputTypes: ["pdf", "docx", "pptx", "markdown", "zip"],
59455
+ capabilities: ["document-generation", "layout", "export-artifacts"]
59456
+ },
59457
+ {
59458
+ name: "structured-data",
59459
+ title: "Structured Data",
59460
+ family: "data",
59461
+ description: "Read, transform, validate, and export CSV, Excel, JSON, SQL, metrics, and tabular datasets.",
59462
+ runtime: "mixed",
59463
+ stable: true,
59464
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59465
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59466
+ apiSurfaces: ["runSkill", "SkillRunArtifact"],
59467
+ envVars: [],
59468
+ outputTypes: ["csv", "xlsx", "json", "sql", "markdown"],
59469
+ capabilities: ["csv", "excel", "etl", "schema", "analytics"]
59470
+ },
59471
+ {
59472
+ name: "media-image",
59473
+ title: "Image Tooling",
59474
+ family: "media",
59475
+ description: "Generate, inspect, transform, remove backgrounds from, and package image artifacts.",
59476
+ runtime: "gateway",
59477
+ stable: true,
59478
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59479
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59480
+ apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
59481
+ envVars: ["SKILLS_API_KEY"],
59482
+ outputTypes: ["png", "jpeg", "webp", "svg", "zip"],
59483
+ capabilities: ["image-generation", "image-analysis", "image-editing", "asset-packaging"]
59484
+ },
59485
+ {
59486
+ name: "media-audio",
59487
+ title: "Audio Tooling",
59488
+ family: "media",
59489
+ description: "Transcribe, extract, clean, generate, and package audio, voiceover, music, and podcast outputs.",
59490
+ runtime: "gateway",
59491
+ stable: true,
59492
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59493
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59494
+ apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
59495
+ envVars: ["SKILLS_API_KEY"],
59496
+ outputTypes: ["mp3", "wav", "txt", "srt", "json", "zip"],
59497
+ capabilities: ["transcription", "audio-generation", "voiceover", "audio-cleanup"]
59498
+ },
59499
+ {
59500
+ name: "media-video",
59501
+ title: "Video Tooling",
59502
+ family: "media",
59503
+ description: "Generate, analyze, cut, caption, summarize, thumbnail, and package video outputs.",
59504
+ runtime: "gateway",
59505
+ stable: true,
59506
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59507
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59508
+ apiSurfaces: ["runSkill", "RemoteSkillRunContract"],
59509
+ envVars: ["SKILLS_API_KEY"],
59510
+ outputTypes: ["mp4", "mov", "srt", "png", "json", "zip"],
59511
+ capabilities: ["video-generation", "video-analysis", "captioning", "highlight-extraction"]
59512
+ },
59513
+ {
59514
+ name: "web-browser",
59515
+ title: "Web Browser",
59516
+ family: "web",
59517
+ description: "Browse, crawl, search, screenshot, inspect, and analyze websites and web application states.",
59518
+ runtime: "mixed",
59519
+ stable: true,
59520
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59521
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59522
+ apiSurfaces: ["runSkill", "SkillRunArtifact"],
59523
+ envVars: [],
59524
+ outputTypes: ["html", "markdown", "png", "json", "har"],
59525
+ capabilities: ["crawl", "browser-automation", "screenshots", "site-analysis"]
59526
+ },
59527
+ {
59528
+ name: "connectors-run",
59529
+ title: "Connector Operations",
59530
+ family: "connectors",
59531
+ description: "Declare and execute external account operations through approved connector plans instead of direct provider CLIs.",
59532
+ runtime: "connector",
59533
+ stable: true,
59534
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59535
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59536
+ apiSurfaces: ["SkillRunContext", "RemoteSkillRunContract"],
59537
+ envVars: ["SKILLS_API_KEY"],
59538
+ outputTypes: ["json", "artifact"],
59539
+ capabilities: ["approval", "external-api", "account-scoped-execution"]
59540
+ },
59541
+ {
59542
+ name: "project-artifacts",
59543
+ title: "Project Artifacts",
59544
+ family: "workspace",
59545
+ description: "Read project context and write deterministic run logs, exports, and downloadable artifacts.",
59546
+ runtime: "local",
59547
+ stable: true,
59548
+ cliCommands: ["skills tools deps <skill>", "skills run <skill>"],
59549
+ mcpTools: ["get_skill_tool_dependencies", "run_skill"],
59550
+ apiSurfaces: ["createSkillRun", "completeSkillRun", "writeRunLogs", "SkillRunArtifact"],
59551
+ envVars: [],
59552
+ outputTypes: ["log", "json", "markdown", "file"],
59553
+ capabilities: ["filesystem", "run-state", "artifact-export", "deterministic-logs"]
59554
+ },
59555
+ {
59556
+ name: "safety-approval",
59557
+ title: "Safety And Approval",
59558
+ family: "safety",
59559
+ description: "Gate risky, paid, security-sensitive, or compliance-sensitive skill actions behind explicit approval and structured evidence.",
59560
+ runtime: "mixed",
59561
+ stable: true,
59562
+ cliCommands: ["skills quote <skill>", "skills tools deps <skill>"],
59563
+ mcpTools: ["quote_skill", "get_skill_tool_dependencies"],
59564
+ apiSurfaces: ["getSkillPricing", "getSkillRunCostCents", "validateSkillDirectory"],
59565
+ envVars: [],
59566
+ outputTypes: ["json", "markdown"],
59567
+ capabilities: ["pricing-approval", "risk-review", "policy-evidence", "validation"]
59568
+ },
59569
+ {
59570
+ name: "hosted-auth",
59571
+ title: "Hosted Auth",
59572
+ family: "hosted",
59573
+ description: "Authenticate hosted and premium runs through Skills account credentials rather than local provider keys.",
59574
+ runtime: "hosted",
59575
+ stable: true,
59576
+ cliCommands: ["skills auth login", "skills billing status", "skills run <skill>"],
59577
+ mcpTools: ["run_skill", "quote_skill"],
59578
+ apiSurfaces: ["RemoteSkillsClient", "RemoteSkillRunContract"],
59579
+ envVars: ["SKILLS_API_KEY"],
59580
+ outputTypes: ["json"],
59581
+ capabilities: ["account-auth", "billing", "remote-run-submit"]
59582
+ }
59583
+ ];
59584
+ CATEGORY_RULES = [
59585
+ { primitive: "ai-gateway", categories: ["Business & Marketing", "Content Generation", "Design & Branding", "Research & Writing", "Education & Learning", "Communication", "Health & Wellness", "Travel & Lifestyle", "Event Management", "Science & Academic"], reason: "Category is primarily AI-assisted generation, analysis, or planning." },
59586
+ { primitive: "project-artifacts", categories: ["Development Tools", "Project Management", "Productivity & Organization"], reason: "Category operates on project context, run logs, or workspace artifacts." },
59587
+ { primitive: "structured-data", categories: ["Data & Analysis", "Finance & Compliance", "Science & Academic"], reason: "Category works with structured inputs, tabular evidence, metrics, or analytical outputs." },
59588
+ { primitive: "safety-approval", categories: ["Finance & Compliance"], reason: "Category has compliance-sensitive outputs that need reviewable evidence." },
59589
+ { primitive: "web-browser", categories: ["Web & Browser"], reason: "Category depends on browser, crawl, search, or web inspection primitives." },
59590
+ { primitive: "media-image", categories: ["Media Processing", "Design & Branding"], reason: "Category includes visual asset generation, inspection, or packaging." }
59591
+ ];
59592
+ NAME_RULES = [
59593
+ { primitive: "documents-read", names: ["read-pdf", "pdf-read", "pdf-to-markdown", "pdf-to-dataset", "doc-read", "extract-invoice", "contract-review-report", "invoice-reconciliation"], reason: "Skill explicitly reads or extracts from document files." },
59594
+ { primitive: "documents-write", names: ["pdf-generate", "doc-generate", "generate-presentation", "slide-deck-generator", "pitch-deck", "proposal-pack", "create-ebook", "generate-book-cover", "api-docs-portal", "landing-page-pack", "one-page-website"], reason: "Skill generates downloadable documents or presentation artifacts." },
59595
+ { primitive: "structured-data", names: ["read-csv", "read-excel", "excel", "generate-sql", "generate-mock-data", "benchmark-finder", "budget-variance-analyzer", "subscription-spend-watcher", "payroll-change-prepper"], reason: "Skill reads, creates, or analyzes structured data." },
59596
+ { primitive: "media-image", names: ["image", "read-image", "brand-photo-shoot", "campaign-moodboard", "logo-design", "icon-pack", "emoji", "product-mockup", "photo-album", "remove-background", "video-thumbnail", "banner-ad-suite", "ad-creative-generator", "ad-creative-pack", "print-collateral-designer", "packaging-concept-studio"], reason: "Skill works directly with image or visual asset primitives." },
59597
+ { primitive: "media-audio", names: ["audio", "music", "transcript", "audio-extract", "audio-transcript-pack", "music-album", "voiceover-jingle-pack", "podcast-show-notes", "subtitle", "audio-cleanup-lab"], reason: "Skill works directly with audio, music, voiceover, or transcription primitives." },
59598
+ { primitive: "media-video", names: ["video", "short-video-pack", "video-highlight-pack", "video-cut-suggester", "video-thumbnail"], reason: "Skill works directly with video generation, editing, captions, or thumbnails." },
59599
+ { primitive: "web-browser", names: ["browse", "webcrawling", "siteanalyze", "performance-audit-report", "seo-content-pack", "competitor-ad-analyzer", "security-audit-report"], reason: "Skill needs live web, crawl, browser, or site inspection primitives." },
59600
+ { primitive: "connectors-run", names: ["email-sequence", "meeting-pack", "customer-feedback-report", "inbox-priority-planner", "crm-note-enhancer", "campaign-metric-brief"], reason: "Skill can execute account-scoped external communication or CRM operations." },
59601
+ { primitive: "safety-approval", names: ["security-audit-report", "contract-review-report", "risk-disclosure-kit", "compliance-report-pack", "procurement-scorecard"], reason: "Skill produces security, legal, compliance, or procurement-sensitive evidence." }
59602
+ ];
59603
+ KEYWORD_RULES = [
59604
+ { primitive: "documents-read", keywords: ["pdf", "docx", "document", "invoice", "contract"], reason: "Skill metadata references document parsing or review." },
59605
+ { primitive: "documents-write", keywords: ["deck", "presentation", "report", "proposal", "ebook", "pdf"], reason: "Skill metadata references generated document artifacts." },
59606
+ { primitive: "structured-data", keywords: ["csv", "excel", "spreadsheet", "dataset", "sql", "metric", "analytics", "scorecard", "budget"], reason: "Skill metadata references tabular or analytical data." },
59607
+ { primitive: "media-image", keywords: ["image", "photo", "logo", "icon", "thumbnail", "visual", "ad creative", "mockup"], reason: "Skill metadata references image or visual assets." },
59608
+ { primitive: "media-audio", keywords: ["audio", "voice", "music", "podcast", "transcript", "subtitle"], reason: "Skill metadata references audio or transcript assets." },
59609
+ { primitive: "media-video", keywords: ["video", "clip", "caption", "highlight"], reason: "Skill metadata references video assets." },
59610
+ { primitive: "web-browser", keywords: ["web", "website", "browser", "crawl", "seo", "landing page", "site"], reason: "Skill metadata references web or browser work." },
59611
+ { primitive: "connectors-run", keywords: ["email", "calendar", "crm", "inbox", "meeting", "outreach"], reason: "Skill metadata references external account operations." }
59612
+ ];
59613
+ primitiveByName = new Map(TOOL_PRIMITIVES.map((primitive) => [primitive.name, primitive]));
59614
+ HOSTED_RUNTIME_SKILL_NAMES = new Set([
59615
+ "audio",
59616
+ "browse",
59617
+ "convert",
59618
+ "image",
59619
+ "music",
59620
+ "pdf-read",
59621
+ "pdf-to-dataset",
59622
+ "pdf-to-markdown",
59623
+ "read-pdf",
59624
+ "transcript",
59625
+ "video",
59626
+ "webcrawling"
59627
+ ]);
59628
+ });
59629
+
59630
+ // src/cli/commands/tool-primitives.ts
59631
+ var exports_tool_primitives = {};
59632
+ __export(exports_tool_primitives, {
59633
+ registerToolPrimitives: () => registerToolPrimitives
59634
+ });
59635
+ function registerToolPrimitives(parent) {
59636
+ const tools = parent.command("tools").description("Inspect primitive tools used by skills, CLI, MCP, and hosted runtimes");
59637
+ tools.command("list").option("--json", "Output as JSON", false).option("--query <query>", "Filter by primitive name, family, runtime, or capability").description("List primitive tools").action((options) => {
59638
+ const primitives = listToolPrimitives(options.query);
59639
+ if (options.json) {
59640
+ console.log(JSON.stringify({ schemaVersion: 1, primitives, total: primitives.length }, null, 2));
59641
+ return;
59642
+ }
59643
+ for (const primitive of primitives) {
59644
+ console.log(`${source_default.bold(primitive.name)} ${source_default.dim(`[${primitive.family}/${primitive.runtime}]`)}`);
59645
+ console.log(` ${primitive.description}`);
59646
+ }
59647
+ });
59648
+ tools.command("info").argument("<primitive>", "Primitive tool name").option("--json", "Output as JSON", false).description("Show primitive tool details").action((name, options) => {
59649
+ const primitive = getToolPrimitive(name);
59650
+ if (!primitive) {
59651
+ if (options.json)
59652
+ console.log(JSON.stringify({ error: `Primitive '${name}' not found` }));
59653
+ else
59654
+ console.error(`Primitive '${name}' not found`);
59655
+ process.exitCode = 1;
59656
+ return;
59657
+ }
59658
+ if (options.json) {
59659
+ console.log(JSON.stringify(primitive, null, 2));
59660
+ return;
59661
+ }
59662
+ console.log(`${source_default.bold(primitive.title)} ${source_default.dim(`[${primitive.name}]`)}`);
59663
+ console.log(primitive.description);
59664
+ console.log(`${source_default.dim("Family:")} ${primitive.family}`);
59665
+ console.log(`${source_default.dim("Runtime:")} ${primitive.runtime}`);
59666
+ if (primitive.capabilities.length)
59667
+ console.log(`${source_default.dim("Capabilities:")} ${primitive.capabilities.join(", ")}`);
59668
+ if (primitive.cliCommands.length)
59669
+ console.log(`${source_default.dim("CLI:")} ${primitive.cliCommands.join(", ")}`);
59670
+ if (primitive.mcpTools.length)
59671
+ console.log(`${source_default.dim("MCP:")} ${primitive.mcpTools.join(", ")}`);
59672
+ });
59673
+ tools.command("deps").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).description("Show primitive tool dependencies for a skill").action((name, options) => {
59674
+ const deps = getSkillToolDependencies(name);
59675
+ if (!deps) {
59676
+ if (options.json)
59677
+ console.log(JSON.stringify({ error: `Skill '${name}' not found` }));
59678
+ else
59679
+ console.error(`Skill '${name}' not found`);
59680
+ process.exitCode = 1;
59681
+ return;
59682
+ }
59683
+ if (options.json) {
59684
+ console.log(JSON.stringify(deps, null, 2));
59685
+ return;
59686
+ }
59687
+ console.log(`${source_default.bold(deps.skill)} ${source_default.dim(`[${deps.category}]`)}`);
59688
+ console.log(`${source_default.dim("Gateway backed:")} ${deps.gatewayBacked ? "yes" : "no"}`);
59689
+ console.log(`${source_default.dim("Hosted runtime:")} ${deps.hostedRuntime ? "yes" : "no"}`);
59690
+ for (const dependency of deps.dependencies) {
59691
+ console.log(` ${source_default.bold(dependency.primitive)} ${source_default.dim(`[${dependency.family}]`)} - ${dependency.reason}`);
59692
+ }
59693
+ });
59694
+ tools.command("validate").option("--json", "Output as JSON", false).option("--profile <profile>", "Registry profile: basic or all", "all").description("Validate primitive tool coverage for the bundled skill catalog").action((options) => {
59695
+ const profile = options.profile === "basic" ? "basic" : "all";
59696
+ const result2 = validateToolPrimitiveCoverage(profile);
59697
+ if (options.json) {
59698
+ console.log(JSON.stringify(result2, null, 2));
59699
+ } else if (result2.valid) {
59700
+ console.log(source_default.green(`Primitive coverage ok: ${result2.mappedSkillCount}/${result2.skillCount} skills mapped to ${result2.primitiveCount} primitives`));
59701
+ console.log(source_default.dim(`Gateway-backed: ${result2.gatewayBackedSkillCount}; hosted runtime: ${result2.hostedRuntimeSkillCount}`));
59702
+ } else {
59703
+ console.log(source_default.red(`Primitive coverage failed: ${result2.issues.length} issue(s)`));
59704
+ for (const issue2 of result2.issues)
59705
+ console.log(source_default.red(` ${issue2.skill}: ${issue2.message}`));
59706
+ }
59707
+ if (!result2.valid)
59708
+ process.exitCode = 1;
59709
+ });
59710
+ }
59711
+ var init_tool_primitives2 = __esm(() => {
59712
+ init_source();
59713
+ init_tool_primitives();
59714
+ });
59715
+
59227
59716
  // src/cli/commands/init.ts
59228
59717
  var exports_init = {};
59229
59718
  __export(exports_init, {
@@ -75157,7 +75646,7 @@ function listMcpToolContracts(query) {
75157
75646
  ].join(" ").toLowerCase();
75158
75647
  return haystack.includes(needle);
75159
75648
  }) : contracts;
75160
- return clone3(filtered);
75649
+ return clone4(filtered);
75161
75650
  }
75162
75651
  function describeMcpToolContracts(names) {
75163
75652
  const byName = new Map(contracts.map((contract) => [contract.name, contract]));
@@ -75171,7 +75660,7 @@ function describeMcpToolContracts(names) {
75171
75660
  params: []
75172
75661
  };
75173
75662
  }
75174
- return { ...clone3(contract), known: true };
75663
+ return { ...clone4(contract), known: true };
75175
75664
  });
75176
75665
  }
75177
75666
  function summarizeMcpToolContract(contract) {
@@ -75185,21 +75674,21 @@ function summarizeMcpToolContract(contract) {
75185
75674
  };
75186
75675
  }
75187
75676
  function getMcpResourceContracts() {
75188
- return clone3(resourceContracts);
75677
+ return clone4(resourceContracts);
75189
75678
  }
75190
75679
  function createMcpContractManifest(options = {}) {
75191
75680
  const selectedNames = options.names ? new Set(options.names) : null;
75192
75681
  const tools = selectedNames ? contracts.filter((contract) => selectedNames.has(contract.name)) : contracts;
75193
75682
  return {
75194
75683
  schemaVersion: MCP_CONTRACT_SCHEMA_VERSION,
75195
- tools: clone3(tools),
75684
+ tools: clone4(tools),
75196
75685
  resources: options.includeResources === false ? [] : getMcpResourceContracts()
75197
75686
  };
75198
75687
  }
75199
75688
  function createSkillMcpMetadata(skill) {
75200
- const installInput = clone3(getRequiredContract("pin_skill").inputSchema);
75201
- const runInput = clone3(getRequiredContract("run_skill").inputSchema);
75202
- const validateInput = clone3(getRequiredContract("validate_skill").inputSchema);
75689
+ const installInput = clone4(getRequiredContract("pin_skill").inputSchema);
75690
+ const runInput = clone4(getRequiredContract("run_skill").inputSchema);
75691
+ const validateInput = clone4(getRequiredContract("validate_skill").inputSchema);
75203
75692
  installInput.properties = {
75204
75693
  ...installInput.properties,
75205
75694
  name: {
@@ -75238,17 +75727,17 @@ function createSkillMcpMetadata(skill) {
75238
75727
  install: {
75239
75728
  tool: "pin_skill",
75240
75729
  inputSchema: installInput,
75241
- outputSchema: clone3(getRequiredContract("pin_skill").outputSchema)
75730
+ outputSchema: clone4(getRequiredContract("pin_skill").outputSchema)
75242
75731
  },
75243
75732
  run: {
75244
75733
  tool: "run_skill",
75245
75734
  inputSchema: runInput,
75246
- outputSchema: clone3(getRequiredContract("run_skill").outputSchema)
75735
+ outputSchema: clone4(getRequiredContract("run_skill").outputSchema)
75247
75736
  },
75248
75737
  validate: {
75249
75738
  tool: "validate_skill",
75250
75739
  inputSchema: validateInput,
75251
- outputSchema: clone3(getRequiredContract("validate_skill").outputSchema)
75740
+ outputSchema: clone4(getRequiredContract("validate_skill").outputSchema)
75252
75741
  }
75253
75742
  }
75254
75743
  };
@@ -75265,7 +75754,7 @@ function getRequiredContract(name) {
75265
75754
  throw new Error(`Missing MCP tool contract: ${name}`);
75266
75755
  return contract;
75267
75756
  }
75268
- function clone3(value) {
75757
+ function clone4(value) {
75269
75758
  return JSON.parse(JSON.stringify(value));
75270
75759
  }
75271
75760
  var MCP_CONTRACT_SCHEMA_VERSION = 1, stringSchema = (description) => ({
@@ -75285,7 +75774,7 @@ var MCP_CONTRACT_SCHEMA_VERSION = 1, stringSchema = (description) => ({
75285
75774
  type: "array",
75286
75775
  items,
75287
75776
  ...description ? { description } : {}
75288
- }), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, paidRunApprovalSchema, errorSchema, pricingSchema, skillSummarySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, contracts, resourceContracts;
75777
+ }), skillNameInput, optionalAgentInput, scopeInput, runInputSchema, runArgsSchema, paidRunApprovalSchema, errorSchema, pricingSchema, skillSummarySchema, toolPrimitiveSummarySchema, skillToolDependencySchema, validationMessageSchema, validationOutputSchema, installOutputSchema, runOutputSchema, toolContracts, contracts, resourceContracts;
75289
75778
  var init_mcp_contracts = __esm(() => {
75290
75779
  skillNameInput = stringSchema("skill name or alias.");
75291
75780
  optionalAgentInput = stringSchema("Optional target agent slug. Use MCP registration instead of direct skill-folder installs.");
@@ -75328,6 +75817,20 @@ var init_mcp_contracts = __esm(() => {
75328
75817
  category: stringSchema("Skill category."),
75329
75818
  pricing: pricingSchema
75330
75819
  }, ["name", "category"], "Compact skill summary.");
75820
+ toolPrimitiveSummarySchema = objectSchema({
75821
+ name: stringSchema("Primitive tool name."),
75822
+ title: stringSchema("Display name."),
75823
+ family: stringSchema("Primitive family."),
75824
+ runtime: stringSchema("Runtime type: local, hosted, gateway, connector, or mixed."),
75825
+ description: stringSchema("Primitive description.")
75826
+ }, ["name", "title", "family", "runtime", "description"], "Primitive tool summary.");
75827
+ skillToolDependencySchema = objectSchema({
75828
+ skill: stringSchema("Skill slug."),
75829
+ primitive: stringSchema("Primitive tool name."),
75830
+ family: stringSchema("Primitive family."),
75831
+ required: { type: "boolean" },
75832
+ reason: stringSchema("Why this skill depends on the primitive.")
75833
+ }, ["skill", "primitive", "family", "required", "reason"], "Primitive dependency for a skill.");
75331
75834
  validationMessageSchema = objectSchema({
75332
75835
  code: stringSchema("Stable validation code."),
75333
75836
  message: stringSchema("Validation message."),
@@ -75508,6 +76011,74 @@ var init_mcp_contracts = __esm(() => {
75508
76011
  inputSchema: objectSchema({ name: skillNameInput }, ["name"]),
75509
76012
  outputSchema: { type: "string", description: "Best available skill documentation." }
75510
76013
  },
76014
+ {
76015
+ name: "list_tool_primitives",
76016
+ title: "List Tool Primitives",
76017
+ description: "List primitive tools used by skills across CLI, MCP, API, and hosted worker execution.",
76018
+ params: ["query?"],
76019
+ category: "discovery",
76020
+ sideEffects: "none",
76021
+ stable: true,
76022
+ inputSchema: objectSchema({ query: stringSchema("Optional primitive search query.") }),
76023
+ outputSchema: objectSchema({
76024
+ schemaVersion: { type: "number" },
76025
+ primitives: arraySchema(toolPrimitiveSummarySchema),
76026
+ total: { type: "number" }
76027
+ }, ["schemaVersion", "primitives", "total"])
76028
+ },
76029
+ {
76030
+ name: "get_tool_primitive",
76031
+ title: "Get Tool Primitive",
76032
+ description: "Get one primitive tool definition by name.",
76033
+ params: ["name"],
76034
+ category: "metadata",
76035
+ sideEffects: "none",
76036
+ stable: true,
76037
+ inputSchema: objectSchema({ name: stringSchema("Primitive tool name.") }, ["name"]),
76038
+ outputSchema: objectSchema({}, [], "Primitive tool definition.", true)
76039
+ },
76040
+ {
76041
+ name: "get_skill_tool_dependencies",
76042
+ title: "Get Skill Tool Dependencies",
76043
+ description: "Get primitive tool dependencies for one skill.",
76044
+ params: ["name"],
76045
+ category: "metadata",
76046
+ sideEffects: "none",
76047
+ stable: true,
76048
+ inputSchema: objectSchema({ name: skillNameInput }, ["name"]),
76049
+ outputSchema: objectSchema({
76050
+ schemaVersion: { type: "number" },
76051
+ skill: skillNameInput,
76052
+ category: stringSchema("Skill category."),
76053
+ source: stringSchema("Skill source."),
76054
+ dependencies: arraySchema(skillToolDependencySchema),
76055
+ gatewayBacked: { type: "boolean" },
76056
+ hostedRuntime: { type: "boolean" }
76057
+ }, ["schemaVersion", "skill", "category", "dependencies", "gatewayBacked", "hostedRuntime"])
76058
+ },
76059
+ {
76060
+ name: "validate_tool_primitives",
76061
+ title: "Validate Tool Primitives",
76062
+ description: "Validate primitive tool coverage for the bundled skill catalog.",
76063
+ params: ["profile?"],
76064
+ category: "validation",
76065
+ sideEffects: "none",
76066
+ stable: true,
76067
+ inputSchema: objectSchema({
76068
+ profile: { type: "string", enum: ["basic", "all"], default: "all" }
76069
+ }),
76070
+ outputSchema: objectSchema({
76071
+ schemaVersion: { type: "number" },
76072
+ valid: { type: "boolean" },
76073
+ profile: stringSchema("Registry profile."),
76074
+ skillCount: { type: "number" },
76075
+ primitiveCount: { type: "number" },
76076
+ mappedSkillCount: { type: "number" },
76077
+ gatewayBackedSkillCount: { type: "number" },
76078
+ hostedRuntimeSkillCount: { type: "number" },
76079
+ issues: arraySchema(objectSchema({}, [], "Coverage issue.", true))
76080
+ }, ["schemaVersion", "valid", "profile", "skillCount", "primitiveCount", "mappedSkillCount", "issues"])
76081
+ },
75511
76082
  {
75512
76083
  name: "pin_skill",
75513
76084
  title: "Pin Skill",
@@ -75900,6 +76471,13 @@ var init_mcp_contracts = __esm(() => {
75900
76471
  mimeType: "application/json",
75901
76472
  schema: arraySchema(skillSummarySchema)
75902
76473
  },
76474
+ {
76475
+ uri: "skills://tool-primitives",
76476
+ name: "Tool Primitives",
76477
+ description: "Primitive tool catalog used by skills across CLI, MCP, API, and hosted workers.",
76478
+ mimeType: "application/json",
76479
+ schema: arraySchema(toolPrimitiveSummarySchema)
76480
+ },
75903
76481
  {
75904
76482
  uri: "skills://{name}",
75905
76483
  name: "Skill Info",
@@ -76074,6 +76652,48 @@ function registerDiscoveryTools(server) {
76074
76652
  }
76075
76653
  return { content: [{ type: "text", text: doc2 }] };
76076
76654
  });
76655
+ server.registerTool("list_tool_primitives", {
76656
+ title: "List Tool Primitives",
76657
+ description: "List primitive tools that skills depend on across CLI, MCP, API, and hosted worker execution.",
76658
+ inputSchema: {
76659
+ query: exports_external.string().optional()
76660
+ }
76661
+ }, async ({ query }) => mcpJson({
76662
+ schemaVersion: 1,
76663
+ primitives: listToolPrimitives(query),
76664
+ total: listToolPrimitives(query).length
76665
+ }));
76666
+ server.registerTool("get_tool_primitive", {
76667
+ title: "Get Tool Primitive",
76668
+ description: "Get one primitive tool definition by name.",
76669
+ inputSchema: {
76670
+ name: exports_external.string()
76671
+ }
76672
+ }, async ({ name }) => {
76673
+ const primitive = getToolPrimitive(name);
76674
+ if (!primitive)
76675
+ return mcpError("PRIMITIVE_NOT_FOUND", `Primitive '${name}' not found`);
76676
+ return mcpJson(primitive);
76677
+ });
76678
+ server.registerTool("get_skill_tool_dependencies", {
76679
+ title: "Get Skill Tool Dependencies",
76680
+ description: "Get primitive tool dependencies for one skill.",
76681
+ inputSchema: {
76682
+ name: exports_external.string()
76683
+ }
76684
+ }, async ({ name }) => {
76685
+ const deps = getSkillToolDependencies(name);
76686
+ if (!deps)
76687
+ return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
76688
+ return mcpJson(deps);
76689
+ });
76690
+ server.registerTool("validate_tool_primitives", {
76691
+ title: "Validate Tool Primitives",
76692
+ description: "Validate primitive tool coverage for the bundled skill catalog.",
76693
+ inputSchema: {
76694
+ profile: exports_external.enum(["basic", "all"]).optional()
76695
+ }
76696
+ }, async ({ profile }) => mcpJson(validateToolPrimitiveCoverage(profile || "all")));
76077
76697
  }
76078
76698
  var init_discovery_tools = __esm(() => {
76079
76699
  init_zod();
@@ -76082,6 +76702,7 @@ var init_discovery_tools = __esm(() => {
76082
76702
  init_skillinfo();
76083
76703
  init_mcp_contracts();
76084
76704
  init_discovery();
76705
+ init_tool_primitives();
76085
76706
  init_helpers();
76086
76707
  });
76087
76708
 
@@ -76750,6 +77371,15 @@ function registerResourceMetaTools(server) {
76750
77371
  mimeType: "application/json"
76751
77372
  }]
76752
77373
  }));
77374
+ server.registerResource("Tool Primitives", "skills://tool-primitives", {
77375
+ description: "Primitive tool catalog used by skills across CLI, MCP, API, and hosted workers."
77376
+ }, async () => ({
77377
+ contents: [{
77378
+ uri: "skills://tool-primitives",
77379
+ text: JSON.stringify(listToolPrimitives(), null, 2),
77380
+ mimeType: "application/json"
77381
+ }]
77382
+ }));
76753
77383
  server.registerResource("Skill Info", new ResourceTemplate("skills://{name}", { list: undefined }), {
76754
77384
  description: "Individual skill metadata and documentation"
76755
77385
  }, async (uri, { name }) => {
@@ -76768,6 +77398,7 @@ function registerResourceMetaTools(server) {
76768
77398
  ...skill ? getPublicSkillDiscovery(skill) : {},
76769
77399
  documentation: skill ? publicDiscoveryDocumentation(skill, doc2) : doc2,
76770
77400
  requirements: publicReqs,
77401
+ toolDependencies: skill ? getSkillToolDependencies(skill.name) : null,
76771
77402
  ...skill ? { mcp: createSkillMcpMetadata(getPublicSkillDiscovery(skill)) } : {}
76772
77403
  }, null, 2),
76773
77404
  mimeType: "application/json"
@@ -76851,6 +77482,7 @@ var init_resource_meta_tools = __esm(() => {
76851
77482
  init_feedback();
76852
77483
  init_mcp_contracts();
76853
77484
  init_discovery();
77485
+ init_tool_primitives();
76854
77486
  init_helpers();
76855
77487
  });
76856
77488
 
@@ -85622,15 +86254,9 @@ function print(value, json, text) {
85622
86254
  else
85623
86255
  console.log(text);
85624
86256
  }
85625
- function hasJsonOption(options) {
85626
- return Boolean(options?.json || options?.opts?.().json || options?.optsWithGlobals?.().json || options?.parent?.opts?.().json || options?.parent?.optsWithGlobals?.().json);
85627
- }
85628
- function wantsJson(actionOptions, command) {
85629
- return hasJsonOption(actionOptions) || hasJsonOption(command);
85630
- }
85631
86257
  function registerWebhookCommands(program2, options) {
85632
86258
  const webhooks = program2.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
85633
- webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
86259
+ webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions) => {
85634
86260
  const timestamp = new Date().toISOString();
85635
86261
  const channel = {
85636
86262
  id: actionOptions.id,
@@ -85651,11 +86277,11 @@ function registerWebhookCommands(program2, options) {
85651
86277
  throw new Error(`Transport ${actionOptions.transport} is reserved for future use and cannot be added yet`);
85652
86278
  }
85653
86279
  const saved = await createClient(options).addChannel(channel);
85654
- print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
86280
+ print(sanitizeChannelForOutput(saved), Boolean(actionOptions.json), `Added ${saved.transport} channel ${saved.id}`);
85655
86281
  });
85656
- webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
86282
+ webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
85657
86283
  const channels = await createClient(options).listChannels();
85658
- if (wantsJson(actionOptions, command)) {
86284
+ if (actionOptions.json) {
85659
86285
  console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
85660
86286
  return;
85661
86287
  }
@@ -85667,11 +86293,11 @@ function registerWebhookCommands(program2, options) {
85667
86293
  console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
85668
86294
  }
85669
86295
  });
85670
- webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
86296
+ webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
85671
86297
  const removed = await createClient(options).removeChannel(id);
85672
- print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
86298
+ print({ removed }, Boolean(actionOptions.json), removed ? `Removed ${id}` : `Channel not found: ${id}`);
85673
86299
  });
85674
- webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
86300
+ webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions) => {
85675
86301
  const result2 = await createClient(options).testChannel(id, {
85676
86302
  source: options.source,
85677
86303
  type: actionOptions.type,
@@ -85679,13 +86305,13 @@ function registerWebhookCommands(program2, options) {
85679
86305
  message: actionOptions.message,
85680
86306
  data: parseJsonObject(actionOptions.data, { test: true })
85681
86307
  });
85682
- print(result2, wantsJson(actionOptions, command), `${result2.status}: ${result2.channelId}`);
86308
+ print(result2, Boolean(actionOptions.json), `${result2.status}: ${result2.channelId}`);
85683
86309
  });
85684
86310
  return webhooks;
85685
86311
  }
85686
86312
  function registerEventCommands(program2, options) {
85687
86313
  const events = program2.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
85688
- events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions, command) => {
86314
+ events.command("emit").description("Emit an event from this app").argument("<type>", "Event type").option("--source <source>", "Event source override").option("--subject <subject>", "Event subject").option("--severity <severity>", "Event severity", "info").option("--message <message>", "Event message").option("--dedupe-key <key>", "Dedupe key").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--no-deliver", "Record without delivering").option("--no-dedupe", "Allow duplicate id/dedupeKey events").option("-j, --json", "Print JSON output", false).action(async (type, actionOptions) => {
85689
86315
  const result2 = await createClient(options).emit({
85690
86316
  source: actionOptions.source ?? options.source,
85691
86317
  type,
@@ -85696,9 +86322,9 @@ function registerEventCommands(program2, options) {
85696
86322
  data: parseJsonObject(actionOptions.data, {}),
85697
86323
  metadata: parseJsonObject(actionOptions.metadata, {})
85698
86324
  }, { deliver: actionOptions.deliver, dedupe: actionOptions.dedupe });
85699
- print(result2, wantsJson(actionOptions, command), `${result2.deduped ? "Deduped" : "Emitted"} ${result2.event.id} to ${result2.deliveries.length} channel(s)`);
86325
+ print(result2, Boolean(actionOptions.json), `${result2.deduped ? "Deduped" : "Emitted"} ${result2.event.id} to ${result2.deliveries.length} channel(s)`);
85700
86326
  });
85701
- events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
86327
+ events.command("list").description("List recorded events").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--limit <n>", "Limit results", parseNumber).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
85702
86328
  let rows = await createClient(options).listEvents();
85703
86329
  if (actionOptions.source)
85704
86330
  rows = rows.filter((event) => event.source === actionOptions.source);
@@ -85706,7 +86332,7 @@ function registerEventCommands(program2, options) {
85706
86332
  rows = rows.filter((event) => event.type === actionOptions.type);
85707
86333
  if (actionOptions.limit)
85708
86334
  rows = rows.slice(-actionOptions.limit);
85709
- if (wantsJson(actionOptions, command)) {
86335
+ if (actionOptions.json) {
85710
86336
  console.log(JSON.stringify(rows, null, 2));
85711
86337
  return;
85712
86338
  }
@@ -85717,14 +86343,14 @@ function registerEventCommands(program2, options) {
85717
86343
  for (const event of rows)
85718
86344
  console.log(`${event.time} ${event.id} ${event.source} ${event.type} ${event.severity}`);
85719
86345
  });
85720
- events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
86346
+ events.command("replay").description("Replay recorded events").option("--id <id>", "Replay one event id").option("--source <source>", "Filter by source").option("--type <type>", "Filter by type").option("--dry-run", "Preview without delivery", false).option("-j, --json", "Print JSON output", false).action(async (actionOptions) => {
85721
86347
  const result2 = await createClient(options).replay({
85722
86348
  eventId: actionOptions.id,
85723
86349
  source: actionOptions.source,
85724
86350
  type: actionOptions.type,
85725
86351
  dryRun: actionOptions.dryRun
85726
86352
  });
85727
- print(result2, wantsJson(actionOptions, command), `Replayed ${result2.events.length} event(s), ${result2.deliveries.length} delivery result(s)`);
86353
+ print(result2, Boolean(actionOptions.json), `Replayed ${result2.events.length} event(s), ${result2.deliveries.length} delivery result(s)`);
85728
86354
  });
85729
86355
  return events;
85730
86356
  }
@@ -86926,6 +87552,8 @@ var { registerBrowse: registerBrowse2 } = await Promise.resolve().then(() => (in
86926
87552
  registerBrowse2(program2);
86927
87553
  var { registerIntrospect: registerIntrospect2 } = await Promise.resolve().then(() => (init_introspect(), exports_introspect));
86928
87554
  registerIntrospect2(program2);
87555
+ var { registerToolPrimitives: registerToolPrimitives2 } = await Promise.resolve().then(() => (init_tool_primitives2(), exports_tool_primitives));
87556
+ registerToolPrimitives2(program2);
86929
87557
  var { registerSetup: registerSetup2 } = await Promise.resolve().then(() => (init_init(), exports_init));
86930
87558
  registerSetup2(program2);
86931
87559
  var { registerDiagnostic: registerDiagnostic2 } = await Promise.resolve().then(() => (init_diagnostic(), exports_diagnostic));