@hasna/skills 0.1.45 → 0.1.47

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/mcp.js CHANGED
@@ -6625,7 +6625,8 @@ var init_skill_aliases = __esm(() => {
6625
6625
  "pdf-reader": "read-pdf",
6626
6626
  "generate-image": "image",
6627
6627
  "image-generator": "image",
6628
- "create-blog-article": "blog-article"
6628
+ "create-blog-article": "blog-article",
6629
+ "skill-diff": "diff-viewer"
6629
6630
  };
6630
6631
  });
6631
6632
 
@@ -7042,7 +7043,7 @@ var init_pricing = __esm(() => {
7042
7043
  { slug: "brand-kit", displayName: "Brand Kit", tier: "premium", costCents: 400, providers: ["hosted"], description: "Hosted brand kit with logo usage, palette, typography, brand voice, sample applications, Markdown guide, PDF guide, and SVG assets" },
7043
7044
  { slug: "generate-book-cover", displayName: "Book Cover", tier: "premium", costCents: 20, providers: ["gpt-image-2"], description: "Professional book cover design from title and genre" },
7044
7045
  { slug: "remove-background", displayName: "Remove Background", tier: "premium", costCents: 10, providers: ["gemini-3-pro"], description: "AI-powered background removal from images" },
7045
- { slug: "transcript", displayName: "Transcript", tier: "premium", costCents: 10, providers: ["whisper"], description: "Audio/video transcription with timestamps" },
7046
+ { slug: "transcript", displayName: "Transcript", tier: "premium", costCents: 10, providers: ["openai", "elevenlabs", "deepgram", "hosted"], description: "Audio/video transcription with timestamps, diarization, and URL support" },
7046
7047
  { slug: "webcrawling", displayName: "Web Crawling", tier: "premium", costCents: 5, providers: ["firecrawl"], description: "Structured web page crawling and extraction" },
7047
7048
  { slug: "browse", displayName: "Browse", tier: "premium", costCents: 5, providers: ["browser"], description: "Web browsing and page interaction" },
7048
7049
  { slug: "read-pdf", displayName: "Read PDF", tier: "premium", costCents: 5, providers: ["cerebras"], description: "Hosted PDF extraction and structured content analysis" },
@@ -18269,7 +18270,7 @@ function finalize(ctx, schema) {
18269
18270
  result.$schema = "http://json-schema.org/draft-07/schema#";
18270
18271
  } else if (ctx.target === "draft-04") {
18271
18272
  result.$schema = "http://json-schema.org/draft-04/schema#";
18272
- } else if (ctx.target === "openapi-3.0") {}
18273
+ } else if (ctx.target === "openapi-3.0") {} else {}
18273
18274
  if (ctx.external?.uri) {
18274
18275
  const id = ctx.external.registry.get(schema)?.id;
18275
18276
  if (!id)
@@ -18517,7 +18518,7 @@ var literalProcessor = (schema, ctx, json, _params) => {
18517
18518
  if (val === undefined) {
18518
18519
  if (ctx.unrepresentable === "throw") {
18519
18520
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
18520
- }
18521
+ } else {}
18521
18522
  } else if (typeof val === "bigint") {
18522
18523
  if (ctx.unrepresentable === "throw") {
18523
18524
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -21797,7 +21798,7 @@ class StdioServerTransport {
21797
21798
  // package.json
21798
21799
  var package_default = {
21799
21800
  name: "@hasna/skills",
21800
- version: "0.1.45",
21801
+ version: "0.1.47",
21801
21802
  description: "Skills library for AI coding agents",
21802
21803
  type: "module",
21803
21804
  bin: {
@@ -21866,7 +21867,7 @@ var package_default = {
21866
21867
  typescript: "^5"
21867
21868
  },
21868
21869
  dependencies: {
21869
- "@hasna/events": "^0.1.3",
21870
+ "@hasna/events": "^0.1.7",
21870
21871
  "@modelcontextprotocol/sdk": "^1.26.0",
21871
21872
  chalk: "^5.3.0",
21872
21873
  commander: "^12.1.0",
@@ -30121,12 +30122,47 @@ function ensurePortableSkillFiles(skillPath, manifest) {
30121
30122
  writeFileSync2(join3(skillPath, "skill.json"), renderSkillJson(next));
30122
30123
  if (!existsSync3(join3(skillPath, "AGENTS.md")))
30123
30124
  writeFileSync2(join3(skillPath, "AGENTS.md"), renderAgentsMd(next));
30124
- if (!existsSync3(join3(skillPath, "package.json")))
30125
- writeFileSync2(join3(skillPath, "package.json"), renderPackageJson(next));
30125
+ ensurePackageJson(skillPath, next);
30126
30126
  if (!existsSync3(join3(skillPath, "tsconfig.json")))
30127
30127
  writeFileSync2(join3(skillPath, "tsconfig.json"), renderTsconfig());
30128
30128
  return readPortableSkillManifest(skillPath, next.name);
30129
30129
  }
30130
+ function ensurePackageJson(skillPath, manifest) {
30131
+ const pkgPath = join3(skillPath, "package.json");
30132
+ const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
30133
+ const commandName = normalizePortableSkillName(first.name || manifest.name);
30134
+ const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
30135
+ if (!existsSync3(pkgPath)) {
30136
+ writeFileSync2(pkgPath, renderPackageJson(manifest));
30137
+ return;
30138
+ }
30139
+ const existing = readJsonObject(pkgPath);
30140
+ const bin = {};
30141
+ if (isRecord(existing.bin)) {
30142
+ for (const [name, value] of Object.entries(existing.bin)) {
30143
+ if (typeof value === "string" && value.trim())
30144
+ bin[normalizePortableSkillName(name)] = value.replace(/^\.\//, "");
30145
+ }
30146
+ } else {
30147
+ const binEntry = stringValue(existing.bin);
30148
+ if (binEntry)
30149
+ bin[manifest.name] = binEntry.replace(/^\.\//, "");
30150
+ }
30151
+ bin[commandName] = entry;
30152
+ const scripts = isRecord(existing.scripts) ? { ...existing.scripts } : {};
30153
+ if (!stringValue(scripts.dev))
30154
+ scripts.dev = `bun run ${entry}`;
30155
+ writeFileSync2(pkgPath, `${JSON.stringify({
30156
+ ...existing,
30157
+ name: manifest.name,
30158
+ version: manifest.version,
30159
+ description: manifest.description,
30160
+ type: stringValue(existing.type) ?? "module",
30161
+ bin,
30162
+ scripts
30163
+ }, null, 2)}
30164
+ `);
30165
+ }
30130
30166
  function copySkillDirectory(source, destination) {
30131
30167
  mkdirSync2(destination, { recursive: true });
30132
30168
  cpSync(source, destination, {
@@ -31566,9 +31602,9 @@ var MEDIA_PROCESSING_SKILLS = [
31566
31602
  {
31567
31603
  name: "transcript",
31568
31604
  displayName: "Transcript",
31569
- description: "Generate transcripts from audio and video files with timestamps",
31605
+ description: "Transcribe audio, video, and media URLs with OpenAI GPT-4o, ElevenLabs Scribe v2, DeepGram, or hosted runtime",
31570
31606
  category: "Media Processing",
31571
- tags: ["transcript", "audio", "video", "speech-to-text"]
31607
+ tags: ["transcript", "audio", "video", "speech-to-text", "diarization", "youtube"]
31572
31608
  },
31573
31609
  {
31574
31610
  name: "video-cut-suggester",
@@ -33012,18 +33048,29 @@ var runOutputSchema = objectSchema({
33012
33048
  exitCode: { type: "number", description: "Process exit code for local runs." },
33013
33049
  skill: stringSchema("Canonical skill slug."),
33014
33050
  remote: { type: "boolean", description: "Whether the skill was submitted to the hosted runtime." },
33015
- stdout: stringSchema("Captured stdout for local runs."),
33016
- stderr: stringSchema("Captured stderr for local runs."),
33051
+ stdoutPreview: objectSchema({
33052
+ text: stringSchema("Truncated stdout preview."),
33053
+ length: { type: "number" },
33054
+ truncated: { type: "boolean" }
33055
+ }, [], "Default compact stdout preview."),
33056
+ stderrPreview: objectSchema({
33057
+ text: stringSchema("Truncated stderr preview."),
33058
+ length: { type: "number" },
33059
+ truncated: { type: "boolean" }
33060
+ }, [], "Default compact stderr preview."),
33061
+ stdout: stringSchema("Captured stdout for local runs when detail:true is requested."),
33062
+ stderr: stringSchema("Captured stderr for local runs when detail:true is requested."),
33017
33063
  id: stringSchema("Remote run id when submitted remotely."),
33018
33064
  localRunId: stringSchema("Local run metadata id."),
33019
33065
  status: stringSchema("Run lifecycle status."),
33020
33066
  pricing: pricingSchema,
33021
- remoteRun: objectSchema({}, [], "Normalized hosted remote run contract.", true),
33022
- run: objectSchema({}, [], "Local run metadata.", true),
33067
+ remoteRun: objectSchema({}, [], "Compact hosted remote run summary by default; full contract when detail:true is requested.", true),
33068
+ run: objectSchema({}, [], "Compact local run metadata by default; full metadata when detail:true is requested.", true),
33023
33069
  nextActions: objectSchema({
33024
33070
  poll: stringSchema("Command to poll run status."),
33025
33071
  download: stringSchema("Command to download artifacts.")
33026
- })
33072
+ }),
33073
+ detailHint: stringSchema("How to request the complete payload.")
33027
33074
  }, [], "Skill run result.");
33028
33075
  var toolContracts = [
33029
33076
  {
@@ -33071,7 +33118,7 @@ var toolContracts = [
33071
33118
  {
33072
33119
  name: "list_skills",
33073
33120
  title: "List Skills",
33074
- description: "List skills from the basic or full registry profile.",
33121
+ description: "List skills from the basic or full registry profile. Returns a compact paged envelope by default.",
33075
33122
  params: ["category?", "profile?", "detail?", "limit?", "offset?"],
33076
33123
  category: "discovery",
33077
33124
  sideEffects: "none",
@@ -33087,7 +33134,11 @@ var toolContracts = [
33087
33134
  skills: arraySchema(skillSummarySchema),
33088
33135
  total: { type: "number" },
33089
33136
  offset: { type: "number" },
33090
- limit: { type: "number" }
33137
+ limit: { type: "number" },
33138
+ nextOffset: { type: "number" },
33139
+ hasMore: { type: "boolean" },
33140
+ nextArguments: objectSchema({}, [], "Arguments for the next page.", true),
33141
+ detailHint: stringSchema("How to request fuller skill objects.")
33091
33142
  })
33092
33143
  },
33093
33144
  {
@@ -33108,7 +33159,7 @@ var toolContracts = [
33108
33159
  {
33109
33160
  name: "search_skills",
33110
33161
  title: "Search Skills",
33111
- description: "Search skills by name, description, or tags.",
33162
+ description: "Search skills by name, description, or tags. Returns a compact paged envelope by default.",
33112
33163
  params: ["query", "profile?", "detail?", "limit?", "offset?"],
33113
33164
  category: "discovery",
33114
33165
  sideEffects: "none",
@@ -33120,7 +33171,16 @@ var toolContracts = [
33120
33171
  limit: { type: "number", minimum: 0 },
33121
33172
  offset: { type: "number", minimum: 0 }
33122
33173
  }, ["query"]),
33123
- outputSchema: objectSchema({ skills: arraySchema(skillSummarySchema) })
33174
+ outputSchema: objectSchema({
33175
+ skills: arraySchema(skillSummarySchema),
33176
+ total: { type: "number" },
33177
+ offset: { type: "number" },
33178
+ limit: { type: "number" },
33179
+ nextOffset: { type: "number" },
33180
+ hasMore: { type: "boolean" },
33181
+ nextArguments: objectSchema({}, [], "Arguments for the next page.", true),
33182
+ detailHint: stringSchema("How to request fuller skill objects.")
33183
+ })
33124
33184
  },
33125
33185
  {
33126
33186
  name: "get_skill_info",
@@ -33237,8 +33297,8 @@ var toolContracts = [
33237
33297
  {
33238
33298
  name: "run_skill",
33239
33299
  title: "Run Skill",
33240
- description: "Run a skill locally or through a configured remote runner.",
33241
- params: ["name", "input?", "args?", "approved?"],
33300
+ description: "Run a skill locally or through a configured remote runner. Returns compact stdout/stderr previews and run summaries by default; pass detail:true for full records.",
33301
+ params: ["name", "input?", "args?", "approved?", "detail?"],
33242
33302
  category: "execution",
33243
33303
  sideEffects: "local-process-or-remote-run",
33244
33304
  stable: true,
@@ -33246,28 +33306,33 @@ var toolContracts = [
33246
33306
  name: skillNameInput,
33247
33307
  input: runInputSchema,
33248
33308
  args: runArgsSchema,
33249
- approved: paidRunApprovalSchema
33309
+ approved: paidRunApprovalSchema,
33310
+ detail: { type: "boolean", default: false, description: "Return full stdout/stderr, remote run, and local run metadata." }
33250
33311
  }, ["name"]),
33251
33312
  outputSchema: runOutputSchema
33252
33313
  },
33253
33314
  {
33254
33315
  name: "get_run_status",
33255
33316
  title: "Get Run Status",
33256
- description: "Fetch remote run status and next actions.",
33257
- params: ["run_id"],
33317
+ description: "Fetch remote run status and next actions. Returns a compact status summary by default; pass detail:true for the complete remote run payload.",
33318
+ params: ["run_id", "detail?"],
33258
33319
  category: "execution",
33259
33320
  sideEffects: "none",
33260
33321
  stable: true,
33261
- inputSchema: objectSchema({ run_id: stringSchema("Remote or local run id.") }, ["run_id"]),
33322
+ inputSchema: objectSchema({
33323
+ run_id: stringSchema("Remote or local run id."),
33324
+ detail: { type: "boolean", default: false, description: "Return the complete remote run payload." }
33325
+ }, ["run_id"]),
33262
33326
  outputSchema: objectSchema({
33263
33327
  contractVersion: { type: "number", description: "Remote run payload contract version." },
33264
33328
  runId: stringSchema("Remote run id."),
33265
33329
  localRunId: stringSchema("Local run id."),
33266
- run: objectSchema({}, [], "Normalized remote run status.", true),
33330
+ run: objectSchema({}, [], "Compact remote run status by default; full status when detail:true is requested.", true),
33267
33331
  nextActions: objectSchema({
33268
33332
  poll: stringSchema("Command to poll run status."),
33269
33333
  download: stringSchema("Command to download artifacts.")
33270
- })
33334
+ }),
33335
+ detailHint: stringSchema("How to request the complete payload.")
33271
33336
  })
33272
33337
  },
33273
33338
  {
@@ -33362,13 +33427,25 @@ var toolContracts = [
33362
33427
  {
33363
33428
  name: "list_schedules",
33364
33429
  title: "List Schedules",
33365
- description: "List scheduled skill runs.",
33366
- params: [],
33430
+ description: "List scheduled skill runs as a compact paged envelope.",
33431
+ params: ["limit?", "offset?"],
33367
33432
  category: "scheduling",
33368
33433
  sideEffects: "none",
33369
33434
  stable: true,
33370
- inputSchema: objectSchema(),
33371
- outputSchema: arraySchema(objectSchema({}, [], "Schedule record.", true))
33435
+ inputSchema: objectSchema({
33436
+ limit: { type: "number", minimum: 0 },
33437
+ offset: { type: "number", minimum: 0 }
33438
+ }),
33439
+ outputSchema: objectSchema({
33440
+ schedules: arraySchema(objectSchema({}, [], "Compact schedule record.", true)),
33441
+ total: { type: "number" },
33442
+ offset: { type: "number" },
33443
+ limit: { type: "number" },
33444
+ nextOffset: { type: "number" },
33445
+ hasMore: { type: "boolean" },
33446
+ nextArguments: objectSchema({}, [], "Arguments for the next page.", true),
33447
+ detailHint: stringSchema("How to request complete schedule details.")
33448
+ })
33372
33449
  },
33373
33450
  {
33374
33451
  name: "remove_schedule",
@@ -33775,6 +33852,90 @@ function resolveDiscoveryPricing(skill) {
33775
33852
  return skill.pricing && typeof skill.pricing.formattedCost === "string" ? skill.pricing : getPublicSkillPricing(skill.name);
33776
33853
  }
33777
33854
 
33855
+ // src/lib/compact-output.ts
33856
+ var DEFAULT_MCP_LIMIT = 25;
33857
+ var MAX_PAGE_LIMIT = 200;
33858
+ var DEFAULT_PREVIEW_CHARS = 600;
33859
+ function truncateText(value, maxChars = 96) {
33860
+ const text = String(value ?? "").replace(/\s+/g, " ").trim();
33861
+ if (text.length <= maxChars)
33862
+ return text;
33863
+ return `${text.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
33864
+ }
33865
+ function previewText(value, maxChars = DEFAULT_PREVIEW_CHARS) {
33866
+ const text = String(value ?? "");
33867
+ return {
33868
+ text: text.length > maxChars ? `${text.slice(0, Math.max(0, maxChars - 3))}...` : text,
33869
+ length: text.length,
33870
+ truncated: text.length > maxChars
33871
+ };
33872
+ }
33873
+ function parsePageLimit(value, fallback, options = {}) {
33874
+ const max = options.max ?? MAX_PAGE_LIMIT;
33875
+ if (typeof value === "string" && options.allowAll && value.trim().toLowerCase() === "all") {
33876
+ return Number.POSITIVE_INFINITY;
33877
+ }
33878
+ const parsed = typeof value === "number" ? value : Number.parseInt(value ?? "", 10);
33879
+ if (!Number.isFinite(parsed))
33880
+ return fallback;
33881
+ if (options.allowAll && parsed === 0)
33882
+ return Number.POSITIVE_INFINITY;
33883
+ if (parsed <= 0)
33884
+ return fallback;
33885
+ return Math.min(parsed, max);
33886
+ }
33887
+ function parsePageOffset(value, fallback = 0) {
33888
+ const parsed = typeof value === "number" ? value : Number.parseInt(value ?? "", 10);
33889
+ if (!Number.isFinite(parsed) || parsed < 0)
33890
+ return fallback;
33891
+ return parsed;
33892
+ }
33893
+ function paginate(items, options) {
33894
+ const offset = Math.min(parsePageOffset(options.offset), items.length);
33895
+ const effectiveLimit = Number.isFinite(options.limit) ? Math.max(0, Math.min(options.limit, MAX_PAGE_LIMIT)) : Math.max(0, items.length - offset);
33896
+ const pageItems = items.slice(offset, offset + effectiveLimit);
33897
+ const nextOffset = offset + pageItems.length < items.length ? offset + pageItems.length : null;
33898
+ return {
33899
+ items: pageItems,
33900
+ total: items.length,
33901
+ offset,
33902
+ limit: effectiveLimit,
33903
+ hasMore: nextOffset !== null,
33904
+ nextOffset
33905
+ };
33906
+ }
33907
+ function compactRunRecord(run) {
33908
+ if (!run || typeof run !== "object")
33909
+ return {};
33910
+ return {
33911
+ id: run.id,
33912
+ skill: run.skill,
33913
+ status: run.status,
33914
+ startedAt: run.startedAt,
33915
+ ...run.completedAt ? { completedAt: run.completedAt } : {},
33916
+ ...run.remoteRunId ? { remoteRunId: run.remoteRunId } : {},
33917
+ ...run.costCents !== undefined ? { costCents: run.costCents } : {},
33918
+ ...run.error ? { error: truncateText(run.error, 240) } : {},
33919
+ artifactCount: Array.isArray(run.artifacts) ? run.artifacts.length : 0,
33920
+ paths: run.paths
33921
+ };
33922
+ }
33923
+ function compactRemoteRun(run) {
33924
+ if (!run || typeof run !== "object")
33925
+ return {};
33926
+ return {
33927
+ ...run.contractVersion !== undefined ? { contractVersion: run.contractVersion } : {},
33928
+ id: run.id,
33929
+ skill: run.skill ?? run.requestedSlug,
33930
+ status: run.status,
33931
+ ...run.correlationId ? { correlationId: run.correlationId } : {},
33932
+ ...run.createdAt ? { createdAt: run.createdAt } : {},
33933
+ ...run.startedAt ? { startedAt: run.startedAt } : {},
33934
+ ...run.completedAt ? { completedAt: run.completedAt } : {},
33935
+ ...run.error || run.errorMessage ? { error: truncateText(run.error ?? run.errorMessage, 240) } : {}
33936
+ };
33937
+ }
33938
+
33778
33939
  // src/mcp/helpers.ts
33779
33940
  function stripNulls(obj) {
33780
33941
  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== undefined && !(Array.isArray(v) && v.length === 0)));
@@ -33823,7 +33984,7 @@ var TOOL_DESCRIPTIONS = getMcpToolDescriptions();
33823
33984
  function registerDiscoveryTools(server) {
33824
33985
  server.registerTool("list_skills", {
33825
33986
  title: "List Skills",
33826
- description: "List skills with public pricing. Defaults to the clean basic profile to avoid context overflow. Set profile:'all' for the full registry. Returns {name,category,pricing} by default; detail:true for full public objects. Supports limit/offset pagination.",
33987
+ description: "List skills with public pricing. Defaults to a compact paged response from the basic profile to avoid context overflow. Set profile:'all' for the full registry, detail:true for full public objects, and use limit/offset to page.",
33827
33988
  inputSchema: {
33828
33989
  category: exports_external.string().optional(),
33829
33990
  profile: exports_external.enum(["basic", "all"]).optional(),
@@ -33835,16 +33996,20 @@ function registerDiscoveryTools(server) {
33835
33996
  const selectedProfile = profile || "basic";
33836
33997
  const skills = category ? loadRegistryProfile(selectedProfile).filter((s) => s.category === category) : loadRegistryProfile(selectedProfile);
33837
33998
  const mapped = detail ? skills.map(getPublicSkillDiscovery) : skills.map(getCompactSkillDiscovery);
33838
- if (limit !== undefined || offset !== undefined) {
33839
- const start = offset || 0;
33840
- const sliced = limit !== undefined ? mapped.slice(start, start + limit) : mapped.slice(start);
33841
- return {
33842
- content: [{ type: "text", text: JSON.stringify({ skills: sliced, total: mapped.length, offset: start, limit: limit ?? null }) }]
33843
- };
33844
- }
33845
- return {
33846
- content: [{ type: "text", text: JSON.stringify(mapped) }]
33847
- };
33999
+ const page = paginate(mapped, {
34000
+ limit: parsePageLimit(limit, DEFAULT_MCP_LIMIT, { max: 100 }),
34001
+ offset: parsePageOffset(offset)
34002
+ });
34003
+ return mcpJson({
34004
+ skills: page.items,
34005
+ total: page.total,
34006
+ offset: page.offset,
34007
+ limit: page.limit,
34008
+ nextOffset: page.nextOffset,
34009
+ hasMore: page.hasMore,
34010
+ nextArguments: page.hasMore ? { profile: selectedProfile, category, detail: Boolean(detail), limit: page.limit, offset: page.nextOffset } : null,
34011
+ detailHint: detail ? undefined : "Set detail:true for full public skill objects, or call get_skill_info for one skill."
34012
+ });
33848
34013
  });
33849
34014
  server.registerTool("list_pinned_skills", {
33850
34015
  title: "List Pinned Skills",
@@ -33861,7 +34026,7 @@ function registerDiscoveryTools(server) {
33861
34026
  });
33862
34027
  server.registerTool("search_skills", {
33863
34028
  title: "Search Skills",
33864
- description: "Search skills by name, description, or tags. Defaults to the clean basic profile; set profile:'all' for the full registry. Returns compact list with pricing by default. Supports limit/offset pagination.",
34029
+ description: "Search skills by name, description, or tags. Defaults to a compact paged response from the basic profile; set profile:'all' for the full registry and detail:true for full public objects.",
33865
34030
  inputSchema: {
33866
34031
  query: exports_external.string(),
33867
34032
  profile: exports_external.enum(["basic", "all"]).optional(),
@@ -33877,16 +34042,20 @@ function registerDiscoveryTools(server) {
33877
34042
  if (!cached2)
33878
34043
  cacheSet(cacheKey, results);
33879
34044
  const out = detail ? results.map(getPublicSkillDiscovery) : results.map(getCompactSkillDiscovery);
33880
- if (limit !== undefined || offset !== undefined) {
33881
- const start = offset || 0;
33882
- const sliced = limit !== undefined ? out.slice(start, start + limit) : out.slice(start);
33883
- return {
33884
- content: [{ type: "text", text: JSON.stringify({ skills: sliced, total: out.length, offset: start, limit: limit ?? null }) }]
33885
- };
33886
- }
33887
- return {
33888
- content: [{ type: "text", text: JSON.stringify(out) }]
33889
- };
34045
+ const page = paginate(out, {
34046
+ limit: parsePageLimit(limit, DEFAULT_MCP_LIMIT, { max: 100 }),
34047
+ offset: parsePageOffset(offset)
34048
+ });
34049
+ return mcpJson({
34050
+ skills: page.items,
34051
+ total: page.total,
34052
+ offset: page.offset,
34053
+ limit: page.limit,
34054
+ nextOffset: page.nextOffset,
34055
+ hasMore: page.hasMore,
34056
+ nextArguments: page.hasMore ? { query, profile: selectedProfile, detail: Boolean(detail), limit: page.limit, offset: page.nextOffset } : null,
34057
+ detailHint: detail ? undefined : "Set detail:true for full public skill objects, or call get_skill_info for one skill."
34058
+ });
33890
34059
  });
33891
34060
  server.registerTool("get_skill_info", {
33892
34061
  title: "Get Skill Info",
@@ -34327,9 +34496,10 @@ function registerOperationTools(server) {
34327
34496
  name: exports_external.string(),
34328
34497
  input: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
34329
34498
  args: exports_external.array(exports_external.string()).optional(),
34330
- approved: exports_external.boolean().optional()
34499
+ approved: exports_external.boolean().optional(),
34500
+ detail: exports_external.boolean().optional()
34331
34501
  }
34332
- }, async ({ name, input, args, approved }) => {
34502
+ }, async ({ name, input, args, approved, detail }) => {
34333
34503
  const skill = getSkill(name);
34334
34504
  if (!skill) {
34335
34505
  return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
@@ -34395,7 +34565,7 @@ function registerOperationTools(server) {
34395
34565
  });
34396
34566
  writeRunLogs(runContext, "", "");
34397
34567
  const remoteRunId = typeof run.id === "string" ? run.id : undefined;
34398
- return mcpJson({
34568
+ const payload2 = {
34399
34569
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
34400
34570
  id: run.id,
34401
34571
  localRunId: localRun2.id,
@@ -34406,7 +34576,8 @@ function registerOperationTools(server) {
34406
34576
  remoteRun: run,
34407
34577
  run: localRun2,
34408
34578
  nextActions: remoteRunNextActions(remoteRunId)
34409
- });
34579
+ };
34580
+ return mcpJson(detail ? payload2 : compactRunToolPayload(payload2, "Call run_skill again with detail:true for full remote/local run records."));
34410
34581
  } catch (err) {
34411
34582
  const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
34412
34583
  writeRunLogs(runContext, "", error48 + `
@@ -34428,23 +34599,23 @@ function registerOperationTools(server) {
34428
34599
  status: result.exitCode === 0 ? "completed" : "failed",
34429
34600
  error: result.error
34430
34601
  });
34602
+ const payload = { exitCode: result.exitCode, skill: skillName, stdout: result.stdout, stderr: result.stderr, run: localRun };
34431
34603
  if (result.error) {
34432
34604
  return {
34433
- content: [{ type: "text", text: JSON.stringify({ exitCode: result.exitCode, error: result.error, run: localRun }, null, 2) }],
34605
+ content: [{ type: "text", text: JSON.stringify(detail ? { ...payload, error: result.error } : compactRunToolPayload({ ...payload, error: result.error }, "Call run_skill again with detail:true for full stdout/stderr and run metadata.")) }],
34434
34606
  isError: true
34435
34607
  };
34436
34608
  }
34437
- return {
34438
- content: [{ type: "text", text: JSON.stringify({ exitCode: result.exitCode, skill: skillName, stdout: result.stdout, stderr: result.stderr, run: localRun }, null, 2) }]
34439
- };
34609
+ return mcpJson(detail ? payload : compactRunToolPayload(payload, "Call run_skill again with detail:true for full stdout/stderr and run metadata."));
34440
34610
  });
34441
34611
  server.registerTool("get_run_status", {
34442
34612
  title: "Get Run Status",
34443
34613
  description: "Fetch remote run status. Accepts a remote run id or a local run id linked to a remote run.",
34444
34614
  inputSchema: {
34445
- run_id: exports_external.string()
34615
+ run_id: exports_external.string(),
34616
+ detail: exports_external.boolean().optional()
34446
34617
  }
34447
- }, async ({ run_id }) => {
34618
+ }, async ({ run_id, detail }) => {
34448
34619
  const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
34449
34620
  const apiKey = getApiKey2();
34450
34621
  if (!apiKey) {
@@ -34461,12 +34632,20 @@ function registerOperationTools(server) {
34461
34632
  const run = await client.getRun(remoteRunId);
34462
34633
  if (!run)
34463
34634
  return mcpError("RUN_NOT_FOUND", `Remote run '${remoteRunId}' not found`);
34464
- return mcpJson({
34635
+ const payload = {
34465
34636
  contractVersion: REMOTE_SKILL_RUN_CONTRACT_VERSION,
34466
34637
  runId: remoteRunId,
34467
34638
  ...localRun ? { localRunId: localRun.id } : {},
34468
34639
  run,
34469
34640
  nextActions: remoteRunNextActions(remoteRunId)
34641
+ };
34642
+ return mcpJson(detail ? payload : {
34643
+ contractVersion: payload.contractVersion,
34644
+ runId: payload.runId,
34645
+ ...localRun ? { localRunId: localRun.id } : {},
34646
+ run: compactRemoteRun(run),
34647
+ nextActions: payload.nextActions,
34648
+ detailHint: "Call get_run_status with detail:true for the complete remote run payload."
34470
34649
  });
34471
34650
  } catch (err) {
34472
34651
  return mcpError("SKILLS_MD_ERROR", err.message);
@@ -34558,6 +34737,32 @@ function registerOperationTools(server) {
34558
34737
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
34559
34738
  });
34560
34739
  }
34740
+ function compactRunToolPayload(payload, detailHint) {
34741
+ const stdout = previewText(payload.stdout ?? "");
34742
+ const stderr = previewText(payload.stderr ?? "");
34743
+ return {
34744
+ ...payload.contractVersion !== undefined ? { contractVersion: payload.contractVersion } : {},
34745
+ ...payload.id !== undefined ? { id: payload.id } : {},
34746
+ ...payload.localRunId !== undefined ? { localRunId: payload.localRunId } : {},
34747
+ ...payload.exitCode !== undefined ? { exitCode: payload.exitCode } : {},
34748
+ skill: payload.skill,
34749
+ ...payload.status !== undefined ? { status: payload.status } : {},
34750
+ ...payload.remote !== undefined ? { remote: payload.remote } : {},
34751
+ ...payload.correlationId !== undefined ? { correlationId: payload.correlationId } : {},
34752
+ ...payload.pricing !== undefined ? { pricing: payload.pricing } : {},
34753
+ ...payload.error !== undefined ? { error: payload.error } : {},
34754
+ ...payload.remoteRun !== undefined ? { remoteRun: compactRemoteRun(payload.remoteRun) } : {},
34755
+ run: compactRunRecord(payload.run),
34756
+ stdoutPreview: stdout,
34757
+ stderrPreview: stderr,
34758
+ stdoutChars: stdout.length,
34759
+ stderrChars: stderr.length,
34760
+ stdoutTruncated: stdout.truncated,
34761
+ stderrTruncated: stderr.truncated,
34762
+ ...payload.nextActions !== undefined ? { nextActions: payload.nextActions } : {},
34763
+ detailHint
34764
+ };
34765
+ }
34561
34766
 
34562
34767
  // src/lib/feedback.ts
34563
34768
  import { existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
@@ -34916,11 +35121,37 @@ function registerScheduleTools(server) {
34916
35121
  });
34917
35122
  server.registerTool("list_schedules", {
34918
35123
  title: "List Schedules",
34919
- description: "List all scheduled skill runs.",
34920
- inputSchema: {}
34921
- }, async () => {
35124
+ description: "List scheduled skill runs as a compact paged response. Use limit/offset for pagination.",
35125
+ inputSchema: {
35126
+ limit: exports_external.number().optional(),
35127
+ offset: exports_external.number().optional()
35128
+ }
35129
+ }, async ({ limit, offset }) => {
34922
35130
  const schedules = listSchedules();
34923
- return { content: [{ type: "text", text: JSON.stringify(schedules, null, 2) }] };
35131
+ const page = paginate(schedules, {
35132
+ limit: parsePageLimit(limit, DEFAULT_MCP_LIMIT, { max: 100 }),
35133
+ offset: parsePageOffset(offset)
35134
+ });
35135
+ return mcpJson({
35136
+ schedules: page.items.map((schedule) => ({
35137
+ id: schedule.id,
35138
+ name: schedule.name,
35139
+ skill: schedule.skill,
35140
+ cron: schedule.cron,
35141
+ enabled: schedule.enabled,
35142
+ lastRun: schedule.lastRun,
35143
+ lastRunStatus: schedule.lastRunStatus,
35144
+ nextRun: schedule.nextRun,
35145
+ argCount: schedule.args?.length ?? 0
35146
+ })),
35147
+ total: page.total,
35148
+ offset: page.offset,
35149
+ limit: page.limit,
35150
+ nextOffset: page.nextOffset,
35151
+ hasMore: page.hasMore,
35152
+ nextArguments: page.hasMore ? { limit: page.limit, offset: page.nextOffset } : null,
35153
+ detailHint: "Use schedule state files or future schedule detail commands for complete schedule records."
35154
+ });
34924
35155
  });
34925
35156
  server.registerTool("remove_schedule", {
34926
35157
  title: "Remove Schedule",