@workerkit/core 0.3.2 → 0.3.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,71 @@ and the package adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.3] - 2026-09-18
10
+
11
+ ### Added
12
+
13
+ Decision workers, reachable outside the dashboard for the first time. A
14
+ decision worker judges items with a typed decision model and routes them by a
15
+ fixed table — no prose, no model turns; its "instruction" is that table plus
16
+ the questions its installer answers, and its run is a receipt of decisions.
17
+ It reaches the same verbs a language worker does, in its own shape, so the
18
+ registry still ships 79 manager and 9 anonymous descriptors.
19
+
20
+ - **`worker_run`** takes `preview` (this run reports and acts on nothing,
21
+ whatever the deployment's mode), `sourceArgs` (narrow what is decided about)
22
+ and `maxItems` on a decision worker, and refuses `prompt` / `modelSlug`
23
+ there with `409 not_language_worker` — the mirror refusal, `409
24
+ not_decision_worker`, guards a language worker against the other four.
25
+ `waitSeconds` (0–55) holds the call until the run settles and answers the
26
+ settled receipt; omit it and the answer is the just-minted receipt, exactly
27
+ as before.
28
+ - **`run_get`** and a waited **`worker_run`** carry a `decision` block on a
29
+ decision run: outcome, confidence, per-item rows with the rule that fired and
30
+ the action taken, findings and openQuestions. It is run content, so it needs
31
+ `readRuns` and comes back withheld without it.
32
+ - **`instruction_get`** answers a decision worker with its routing table as
33
+ sentences, its install questions with their current answers, the ones still
34
+ pending (a pending question blocks both deploy and run) and the live/preview
35
+ mode. `optionsFor` asks one `appPick` question for its live options from the
36
+ worker's own connected app — never a 4xx: an app that cannot answer returns
37
+ an empty list with a warning saying why. The tool sent no query parameters
38
+ before, so it passes them through now.
39
+ - **`instruction_set`** takes `answers` instead of `content` there — a partial
40
+ map, where `''` clears one. Same `manageInstructions` scope either way, and
41
+ the two are mutually exclusive.
42
+
43
+ The authoring and install fields for the kits that carry these workers:
44
+
45
+ - **`kit_install`** takes `decisionAnswers` (the preview's `decisionSetup`
46
+ questions, by key).
47
+ - **`deployment_update`** takes `decisionMode`: `live` (the default — the
48
+ routing table's actions execute) or `preview` (every run reports what it
49
+ would do and acts on nothing).
50
+ - **`kits_search`** takes `modelType` (`language` | `decision`) and its cards
51
+ carry it; `directory_overview` answers the `modelTypes` vocabulary.
52
+ - `kit_publish` / `kit_validate` / `kit_replace` content names `decisionSpec`
53
+ and `modelType`, and `kit_install_preview`, `kit_get`, `worker_deploy` and
54
+ `models_list` describe the decision-kit fields and refusals
55
+ (`decision_setup_pending`) they already carried.
56
+
57
+ ### Changed
58
+
59
+ - **`worker_get`** reports `modelType` and, on a decision worker,
60
+ `decisionPendingSetup` — the install questions still blank. It is the field
61
+ that says which of the above a call will accept.
62
+ - **`worker_deploy`**'s model refusals are named as the server sends them
63
+ today: `400 invalid_model` and `400 model_tier_gated`, replacing
64
+ `model_unavailable` / `model_tier` in the description.
65
+ - **`instruction_set`**'s `content` is now optional, so `jobSentence`,
66
+ `whenToUse` and `description` can be changed on their own without resending
67
+ the whole instruction. It was mandatory before, which the `answers` path also
68
+ needed lifted.
69
+ - A description pass across both registries: the shared notes (grading,
70
+ delivery, cloning, deployment, the new-scope note) and the longest tool
71
+ descriptions say the same contract in fewer words. No parameter, path, body
72
+ or annotation changed with it.
73
+
9
74
  ## [0.3.2] - 2026-09-12
10
75
 
11
76
  ### Added
@@ -1 +1 @@
1
- {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/descriptors/directory.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAsB5D,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAapC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,GAAG,SAAS,CAYhG;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAM3D;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAQ9F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAclG;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAYlG;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAsND,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EAUzD,CAAC"}
1
+ {"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/descriptors/directory.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAsB5D,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAapC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,GAAE,MAA0B,GAAG,MAAM,GAAG,SAAS,CAYhG;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,SAAS,CAM3D;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAQ9F;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAclG;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAYlG;AAED,8FAA8F;AAC9F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAOrE;AAyND,eAAO,MAAM,oBAAoB,EAAE,SAAS,cAAc,EAUzD,CAAC"}
@@ -23,11 +23,11 @@ const SITE = "https://workerkit.ai";
23
23
  const SLUG_HINT = "The kit's URL slug, as returned by kits_search (slug).";
24
24
  // Appended to every tool: the two facts an agent must never get wrong on a
25
25
  // public mount — no auth exists, and installing is out of its reach.
26
- const DIRECTORY_NOTE = " The directory is public: no authentication, no account needed, and results are identical for everyone. No tool here can install or publish. A kit is installed by a signed-in human on its workerkit.ai page (offer the page URL), or by an authenticated agent via the kit_install_preview / kit_install tools on the WorkerKit Manager MCP server (the /workers mount — manager key with the installKits scope); a kit is AUTHORED with kit_authoring_guide + kit_vocabulary here, then validated and published on that same /workers mount (kit_validate / kit_publish, publishKits scope).";
26
+ const DIRECTORY_NOTE = " Public and anonymous: results are identical for everyone, and nothing here installs or publishes. Install: a signed-in human on the kit's workerkit.ai page (offer the URL), or an agent with the installKits scope via kit_install_preview / kit_install on the WorkerKit Manager mount (/workers). Author: kit_authoring_guide + kit_vocabulary here, then kit_validate / kit_publish on /workers (publishKits scope).";
27
27
  // The two authoring reads share one framing: they are what an agent reads BEFORE
28
28
  // writing a kit for the manager surface, and they are anonymous so it can draft
29
29
  // before it holds any credential.
30
- const AUTHORING_NOTE = " The directory is public: no authentication, no account needed, and this read is identical for everyone. The kit itself is validated and published on the authenticated WorkerKit Manager MCP server (the /workers mount): kit_validate (dry run — every section's verdict at once) then kit_publish, both behind the publishKits scope. Publish PRIVATE first (visibility 'private'): a private kit is installable only by its own account — by a signed-in human on its workerkit.ai page, or by an agent via kit_install — which is also how a worker is created from scratch. A worker can only use apps that are CONNECTED on its operator: apps_list on the /workers mount says which are, and app_connect connects the credential-based ones. An app the platform does not offer can still be reached through its MCP server: mcp_server_create on the /workers mount registers it as the account's own custom MCP app (credential included), mcp_server_set_tools enables its tools, and the kit binds it in content.mcpServers.";
30
+ const AUTHORING_NOTE = " Public and anonymous, identical for everyone. The kit is validated and published on the WorkerKit Manager mount (/workers): kit_validate (every section's verdict at once), then kit_publish — publishKits scope. Publish PRIVATE first (visibility 'private'): a private kit installs only on its own account (a signed-in human on its workerkit.ai page, or an agent via kit_install), which is also how a worker is created from scratch. A worker uses only apps CONNECTED on its operator (apps_list; app_connect for credential-based ones). An app the platform lacks is added as the account's own custom MCP app: mcp_server_create (credential included), mcp_server_set_tools, then content.mcpServers in the kit.";
31
31
  const SEARCH_EMPTY_HINT = "No kits matched. Filters AND together — drop some. query is a plain case-insensitive substring over name + job sentence (one short word beats a phrase), and unknown category/app/publisher values match nothing rather than erroring. directory_overview lists every valid filter value. If nothing fits after broadening, author a kit for the exact job rather than installing a near miss: kit_authoring_guide (index, then schema and rules) and kit_app_tools here, then kit_validate and kit_publish (private) on the /workers mount, then kit_install.";
32
32
  // publisher_get accepts no search filters, so the search hint above would tell an
33
33
  // agent to broaden filters it never set. Reachable: the profile 404s only when the
@@ -114,7 +114,7 @@ export function publisherPageFooter(data) {
114
114
  const directoryOverview = {
115
115
  name: "directory_overview",
116
116
  title: "Directory Overview",
117
- description: "The directory's vocabulary and scale in one call — call this FIRST when you need valid kits_search filter values or a map of what WorkerKit covers. Returns: kitCount (published kits right now); categories grouped as jobFamilies/roles/industries ({slug, name} — slugs feed the category/industry filters); apps ({code, name, categoryCode?, installable} — codes feed the app filter; installable:false means kits can show the app but an install cannot carry it); appCategories ({code, name, members:[{code, name, appCode}]} — codes feed the appCategory filter; members are what an installer picks between, e.g. Slack vs Teams); models ({model, normalized, kitCount} — pass normalized or any substring as the model filter); sortOptions; triggerModes. Vocabulary only — it lists no kits: for 'what is popular', use kits_search with the default downloads sort. Kit pages for humans follow https://workerkit.ai/kit/{slug}." +
117
+ description: "The directory's vocabulary and scale in one call — call this FIRST when you need valid kits_search filter values or a map of what WorkerKit covers. Returns: kitCount (published kits right now); categories grouped as jobFamilies/roles/industries ({slug, name} — slugs feed the category/industry filters); apps ({code, name, categoryCode?, installable} — codes feed the app filter; installable:false means kits can show the app but an install cannot carry it); appCategories ({code, name, members:[{code, name, appCode}]} — codes feed the appCategory filter; members are what an installer picks between, e.g. Slack vs Teams); models ({model, normalized, kitCount} — pass normalized or any substring as the model filter); modelTypes ({code, name, summary} — 'language' | 'decision', each with its one-line summary; codes feed the modelType filter); sortOptions; triggerModes. Vocabulary only — it lists no kits: for 'what is popular', use kits_search with the default downloads sort. Kit pages for humans follow https://workerkit.ai/kit/{slug}." +
118
118
  DIRECTORY_NOTE,
119
119
  auth: "anonymous",
120
120
  method: "get",
@@ -125,7 +125,7 @@ const directoryOverview = {
125
125
  const searchKits = {
126
126
  name: "kits_search",
127
127
  title: "Search Kits",
128
- description: "Search and browse the public WorkerKit kits directory. A kit is a pre-built AI worker template — a job instruction plus exact, pre-scoped app permissions (and often schedules) — that a human installs as a working AI worker in one click. All filters AND together; every value is optional (omit everything to browse the whole catalog). Returns {items, totalCount, page, pageSize}; each card: slug (the key for kit_get), name, jobSentence (what the worker does, one line), publisherName/publisherSlug/isOfficialPublisher/verificationTier, apps (app codes it uses) + categorySlots (capability slots where the installer picks the app, e.g. Slack vs Teams), categories, triggerModes, downloadCount, starCount, modelScores (publisher-declared 0-100 fit per model, best first) + recommendedModel, isProtected (publisher withholds the instruction TEXT; the kit still fully works — not a red flag), isFeatured, publishedAt. An empty result is not an error — see the footer it returns; valid category/app/appCategory/model filter values come from directory_overview. Kit page for humans: https://workerkit.ai/kit/{slug}." +
128
+ description: "Search and browse the public WorkerKit kits directory. A kit is a pre-built AI worker template — a job instruction plus exact, pre-scoped app permissions (and often schedules) — that a human installs as a working AI worker in one click. All filters AND together; every value is optional (omit everything to browse the whole catalog). Returns {items, totalCount, page, pageSize}; each card: slug (the key for kit_get), name, jobSentence (what the worker does, one line), publisherName/publisherSlug/isOfficialPublisher/verificationTier, apps (app codes it uses) + categorySlots (capability slots where the installer picks the app, e.g. Slack vs Teams), categories, triggerModes, downloadCount, starCount, modelScores (publisher-declared 0-100 fit per model, best first) + recommendedModel, modelType ('language' | 'decision' — see the filter), isProtected (publisher withholds the instruction TEXT; the kit still fully works — not a red flag), isFeatured, publishedAt. An empty result is not an error — see the footer it returns; valid category/app/appCategory/model filter values come from directory_overview. Kit page for humans: https://workerkit.ai/kit/{slug}." +
129
129
  DIRECTORY_NOTE,
130
130
  auth: "anonymous",
131
131
  method: "get",
@@ -137,6 +137,7 @@ const searchKits = {
137
137
  appCategory: z.string().optional().describe("Capability-category code, e.g. 'team-collaboration': matches kits that define that install-time slot OR pin one of its member apps — broader than the app filter. Unknown codes error (the error names the fix). Valid codes: directory_overview → appCategories."),
138
138
  model: z.string().max(80).optional().describe("Substring match on a scored model name, e.g. 'sonnet' or 'gpt'. Valid names: directory_overview → models."),
139
139
  trigger: z.enum(["onDemand", "scheduled", "event"]).optional().describe("How the kit's worker runs: onDemand (a human or agent triggers it), scheduled (ships recurring schedules), event (webhook-triggered)."),
140
+ modelType: z.enum(["language", "decision"]).optional().describe("language = an instruction the installer runs on a model of their choice; decision = a routing table the decision model applies per item (triage, sorting, labelling, filtering — no instruction, no model to pick). Omit for both."),
140
141
  publisher: z.string().optional().describe("Publisher slug (publisherSlug on any card) — that publisher's kits only."),
141
142
  sort: z.enum(["downloads", "new", "name", "stars"]).default("downloads").describe("downloads = most installed (the popularity signal), new = latest published, name = A-Z, stars = most starred."),
142
143
  page: z.number().int().min(1).default(1).describe("1-based page number."),
@@ -155,7 +156,7 @@ const searchKits = {
155
156
  const getKit = {
156
157
  name: "kit_get",
157
158
  title: "Get Kit",
158
- description: "One kit's full public dossier — everything a human (or an agent advising one) can evaluate before installing. Key fields: description + appDescriptions (author's per-app/per-tool notes); instructionContent — the worker's job instruction VERBATIM, the core of what you are evaluating (empty string when isProtected while instructionLength still reports the real size; startCommand/endCommand/whenToUse are null on a protected kit, deliberately indistinguishable from 'none'); permissionsManifest — the EXACT data access an install grants (per-app operations/fields/scopes; numeric value is authoritative, names/keys are display) — summarize THIS when asked what the kit can touch; requiredInputs + memorySetup — the install form: fields the kit needs and questions whose answers become the worker's memory; memoryProfile ('contextual' = the worker is shown its own recent runs) and selfFactsEnabled (the worker saves durable facts on its own); schedules/triggers/usageWindows; skillResources — reference docs the worker fetches on demand: key/kind/name always, plus description/contentLength on a non-protected kit (a protected kit lists identity only), body via includeResourceBodies; hasExternalMcpShells — TRUE means installing creates an MCP gateway in the installer's account pointing at the publisher's own upstream URL (permissionsManifest.mcpServers.shells) — surface this when recommending; scan — the security scan's result for the text being served: outcome 'cleared' or 'underReview' (BOTH are live, installable listings; 'underReview' means a check raised something a reviewer has not settled, never that the kit is unsafe), scannedAtUtc (null = published before the scanner existed, which is most of the catalog), checks — the check families that actually ran on THIS kit, so 'cleared' with only ['static'] is a weaker statement than 'cleared' with all three; and recommendation ('safe' | 'caution' | 'doNotInstall') — the SCANNER's own install advice about the content, which is independent of outcome (our moderation state) and may legitimately disagree with it, so attribute it to SkillSpector rather than to WorkerKit when you repeat it, and read 'caution' as 'worth a look', not as danger (the scanner also emits it when its own analysis was incomplete); scan is absent for a kit with nothing to report, and it never carries the findings themselves; modelScores (with notes), downloadCount/starCount, and pageUrl — the install page to hand to the human. 404 = no published kit with that slug." +
159
+ description: "One kit's full public dossier — what a human, or an agent advising one, evaluates before installing. Fields: description + appDescriptions (the author's per-app / per-tool notes); modelType ('language', the default, or 'decision'); instructionContent — a language kit's job instruction VERBATIM, the core of what you are evaluating (empty when isProtected, with instructionLength still real; startCommand / endCommand / whenToUse are null on a protected kit, indistinguishable from 'none'); on a DECISION kit evaluate decisionNarration instead (what it reads, the questions it asks each item, the rules that route them, what happens below the confidence floor — served on protected kits too) and decisionSetup (the questions its installer answers); permissionsManifest — the EXACT data access an install grants (per-app operations / fields / scopes; the numeric value is authoritative, names are display) — summarize THIS when asked what the kit can touch; requiredInputs + memorySetup — the install form (fields the kit needs, questions whose answers become the worker's memory); memoryProfile ('contextual' = the worker sees its own recent runs) and selfFactsEnabled (it saves durable facts on its own); schedules / triggers / usageWindows; skillResources — reference docs the worker fetches on demand (key / kind / name always; description / contentLength unless protected; bodies via includeResourceBodies); hasExternalMcpShells — TRUE means installing creates an MCP gateway in the installer's account pointing at the publisher's own upstream URL (permissionsManifest.mcpServers.shells): surface it when recommending; scan — the security scan of the text being served: outcome 'cleared' or 'underReview' (both are live, installable listings — 'underReview' means a reviewer has not settled a raised check, never that the kit is unsafe), scannedAtUtc (null = published before the scanner existed, most of the catalog), checks (the families that ran on THIS kit — 'cleared' on ['static'] alone is weaker than on all three) and recommendation ('safe' | 'caution' | 'doNotInstall', the SCANNER's own advice, independent of outcome and possibly disagreeing with it: attribute it to SkillSpector, and read 'caution' as 'worth a look' — it is also emitted when the analysis was incomplete); scan is absent when there is nothing to report and never carries findings; modelScores (with notes), downloadCount / starCount, and pageUrl — the install page to hand to the human. 404 = no published kit with that slug." +
159
160
  DIRECTORY_NOTE,
160
161
  auth: "anonymous",
161
162
  method: "get",
@@ -226,7 +227,7 @@ const kitAuthoringGuide = {
226
227
  const kitVocabulary = {
227
228
  name: "kit_vocabulary",
228
229
  title: "Kit Authoring Vocabulary",
229
- description: "The live vocabulary a kit's permission manifest accepts — read it before writing content.apps / content.categorySlots / categorySlugs, because every key is validated strictly and there is no 'all' shorthand. Without app: everything except per-app tools — apps[] (per surface: code, name, summary, operations = the tool KEYS you grant, fields, and every axis it supports: readOperations, masterAccessLevels, writableFields, providers, channels, objectTypes, scopePolicies, contentTypeScopes, capabilities, supportsAllowAll, supportsWriteEnabled, subApps, installable), concreteApps[] (vendor tiles like Gmail, Monday, Google Sheets with kind standalone|provider|slotMember|subApp — how each lands in content), appCategories[] (the capability slots with members, labelAlias, genericName), categories {jobFamilies, roles, industries} (the ONLY valid categorySlugs), models[], mcpApps[] (platform MCP apps a kit may bind via content.mcpServers — id is the gatewayId, tools[].toolId the toolIds; an account's OWN servers are on the /workers mount's mcp_servers_list instead), and note. With app=<code>: that ONE surface as {app, vendors, tools, note} where tools are what an installed worker sees on it — each {name (cite this in the instruction), description, readOnly, requires (grant at least one of these keys under operations to get the tool)}; toolsNote replaces tools on a surface no catalog covers. The full read is large: take it once per authoring task, then per-app reads for the surfaces you use. To explore what every app can do before choosing, kit_app_tools is the one-call view. An unknown app is a 400 naming every valid code." +
230
+ description: "The live vocabulary a kit's permission manifest accepts — read it before writing content.apps / content.categorySlots / categorySlugs: every key is validated strictly and there is no 'all' shorthand. Without app: apps[] (per surface: code, name, summary, operations = the tool KEYS you grant, fields, and every axis it supports — readOperations, masterAccessLevels, writableFields, providers, channels, objectTypes, scopePolicies, contentTypeScopes, capabilities, supportsAllowAll, supportsWriteEnabled, subApps, installable), concreteApps[] (vendor tiles such as Gmail, Monday or Google Sheets, kind standalone | provider | slotMember | subApp — how each lands in content), appCategories[] (the capability slots: members, labelAlias, genericName), categories {jobFamilies, roles, industries} (the ONLY valid categorySlugs), models[], mcpApps[] (platform MCP apps a kit binds via content.mcpServers — id is the gatewayId, tools[].toolId the toolIds; the account's OWN servers are mcp_servers_list on /workers) and note. With app=<code>: that ONE surface as {app, vendors, tools, note}, tools being what an installed worker sees — each {name (cite it in the instruction), description, readOnly, requires (grant one of these keys under operations to get the tool)}; toolsNote replaces tools where no catalog covers the surface. The full read is large: take it once per authoring task, then per-app reads for the surfaces you use; kit_app_tools is the one-call view of what every app can do. Unknown app = 400 naming every valid code." +
230
231
  AUTHORING_NOTE,
231
232
  auth: "anonymous",
232
233
  method: "get",
@@ -1 +1 @@
1
- {"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/descriptors/directory.ts"],"names":[],"mappings":"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","sourcesContent":["// The public kits-directory tools: anonymous, read-only catalog tools over the\n// public directory API. Nine tools rather than one per REST endpoint — the about read\n// (what WorkerKit is and when an agent should reach for it), one vocabulary\n// call, one search, one dossier, one stats read, one publisher profile, and the\n// three authoring reads (the guide, the permission vocabulary an author needs,\n// and the explorer of what each app lets a worker do).\n//\n// The upstream surface is already agent-shaped (always-anonymous, no\n// viewer-scoped fields, opt-in skill-resource bodies, composed overview), so\n// these tools stay thin passthroughs. What lives HERE is the pure half of the\n// presentation an MCP server (or CLI) should not each reinvent:\n// - Empty search results append a broaden-this hint; truncated results append\n// the next page number — the two places agents reliably mis-step.\n// - kit_get / publisher_get carry a computed pageUrl: nothing on an anonymous\n// surface can install, so the agent hands over the link — or, when it holds\n// a manager key with the installKits scope, installs via kit_install_preview\n// / kit_install on the authenticated WorkerKit Manager server.\n\nimport { z } from \"../zod.js\";\nimport { READ_ONLY, type ToolDescriptor } from \"./types.js\";\n\nconst API = \"/api/directory/mcp\";\nconst SITE = \"https://workerkit.ai\";\n\n// ─── Shared phrasing ────────────────────────────────────────────────────────\n\nconst SLUG_HINT = \"The kit's URL slug, as returned by kits_search (slug).\";\n\n// Appended to every tool: the two facts an agent must never get wrong on a\n// public mount — no auth exists, and installing is out of its reach.\nconst DIRECTORY_NOTE =\n \" The directory is public: no authentication, no account needed, and results are identical for everyone. No tool here can install or publish. A kit is installed by a signed-in human on its workerkit.ai page (offer the page URL), or by an authenticated agent via the kit_install_preview / kit_install tools on the WorkerKit Manager MCP server (the /workers mount — manager key with the installKits scope); a kit is AUTHORED with kit_authoring_guide + kit_vocabulary here, then validated and published on that same /workers mount (kit_validate / kit_publish, publishKits scope).\";\n\n// The two authoring reads share one framing: they are what an agent reads BEFORE\n// writing a kit for the manager surface, and they are anonymous so it can draft\n// before it holds any credential.\nconst AUTHORING_NOTE =\n \" The directory is public: no authentication, no account needed, and this read is identical for everyone. The kit itself is validated and published on the authenticated WorkerKit Manager MCP server (the /workers mount): kit_validate (dry run — every section's verdict at once) then kit_publish, both behind the publishKits scope. Publish PRIVATE first (visibility 'private'): a private kit is installable only by its own account — by a signed-in human on its workerkit.ai page, or by an agent via kit_install — which is also how a worker is created from scratch. A worker can only use apps that are CONNECTED on its operator: apps_list on the /workers mount says which are, and app_connect connects the credential-based ones. An app the platform does not offer can still be reached through its MCP server: mcp_server_create on the /workers mount registers it as the account's own custom MCP app (credential included), mcp_server_set_tools enables its tools, and the kit binds it in content.mcpServers.\";\n\n// ─── Pure data mappers + footers (presentation data, not ToolResult assembly) ─\n\ntype Json = Record<string, unknown>;\n\nconst SEARCH_EMPTY_HINT =\n \"No kits matched. Filters AND together — drop some. query is a plain case-insensitive substring over name + job sentence (one short word beats a phrase), and unknown category/app/publisher values match nothing rather than erroring. directory_overview lists every valid filter value. If nothing fits after broadening, author a kit for the exact job rather than installing a near miss: kit_authoring_guide (index, then schema and rules) and kit_app_tools here, then kit_validate and kit_publish (private) on the /workers mount, then kit_install.\";\n\n// publisher_get accepts no search filters, so the search hint above would tell an\n// agent to broaden filters it never set. Reachable: the profile 404s only when the\n// publisher has no PUBLISHED kits, while the catalog list additionally excludes\n// taken-down ones — so a publisher whose only published kit was moderated out\n// returns 200 with an empty items array.\nconst PUBLISHER_EMPTY_HINT =\n \"This publisher currently lists no kits (publisher.kitCount can still be non-zero — a published kit can be withheld from the catalog). publisher_get takes no search filters, so there is nothing to broaden; report the profile as-is.\";\n\n/**\n * The one footer a {items, totalCount, page, pageSize} list needs: how to\n * broaden when nothing matched, or which page comes next when truncated.\n */\nexport function listFooter(body: Json, emptyHint: string = SEARCH_EMPTY_HINT): string | undefined {\n const items = Array.isArray(body.items) ? body.items : [];\n const totalCount = typeof body.totalCount === \"number\" ? body.totalCount : items.length;\n const page = typeof body.page === \"number\" ? body.page : 1;\n const pageSize = typeof body.pageSize === \"number\" && body.pageSize > 0 ? body.pageSize : Math.max(items.length, 1);\n if (totalCount === 0) {\n return emptyHint;\n }\n if (page * pageSize < totalCount) {\n return `Showing page ${page} of ${Math.ceil(totalCount / pageSize)} (${totalCount} kits total) — call again with page: ${page + 1} for more`;\n }\n return undefined;\n}\n\n/** kits_search data: the validated list body, or undefined = serve verbatim. */\nexport function kitListData(data: unknown): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || !Array.isArray((body as Json).items)) {\n return undefined; // unexpected shape — serve verbatim rather than guess\n }\n return body;\n}\n\n/** kit_get data: the dossier with the computed pageUrl, or undefined = verbatim. */\nexport function kitDetailData(data: unknown, params: Record<string, unknown>): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return undefined;\n\n const detail = { ...body };\n const slug = typeof detail.slug === \"string\" && detail.slug.length > 0 ? detail.slug : String(params.slug ?? \"\");\n detail.pageUrl = `${SITE}/kit/${encodeURIComponent(slug)}`;\n return detail;\n}\n\n/**\n * kit_get footer. Bodies exist upstream but were not requested: each such\n * resource reports a contentLength with no content. A protected kit's resources\n * carry neither (identity-only), so this stays silent there — re-calling would\n * not help.\n */\nexport function kitDetailFooter(data: unknown, params: Record<string, unknown>): string | undefined {\n const detail = data as Json;\n if (params.includeResourceBodies !== true && Array.isArray(detail.skillResources)) {\n const omitted = detail.skillResources.filter(\n (r) =>\n r !== null && typeof r === \"object\" && !Array.isArray(r) &&\n typeof (r as Json).contentLength === \"number\" && ((r as Json).contentLength as number) > 0 &&\n typeof (r as Json).content !== \"string\"\n ).length;\n if (omitted > 0) {\n return `${omitted} skillResources ${omitted === 1 ? \"body\" : \"bodies\"} omitted — call again with includeResourceBodies: true to read them`;\n }\n }\n return undefined;\n}\n\n/** publisher_get data: the profile with the computed pageUrl, or undefined = verbatim. */\nexport function publisherPageData(data: unknown, params: Record<string, unknown>): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return undefined;\n\n const page = { ...body };\n const publisher = page.publisher as Json | undefined;\n const slug =\n publisher && typeof publisher.slug === \"string\" && publisher.slug.length > 0\n ? publisher.slug\n : String(params.slug ?? \"\");\n page.pageUrl = `${SITE}/publishers/${encodeURIComponent(slug)}`;\n return page;\n}\n\n/** publisher_get footer: pages the embedded kit list with the publisher-shaped empty hint. */\nexport function publisherPageFooter(data: unknown): string | undefined {\n const page = data as Json;\n const kits = page.kits;\n if (kits && typeof kits === \"object\" && !Array.isArray(kits) && Array.isArray((kits as Json).items)) {\n return listFooter(kits as Json, PUBLISHER_EMPTY_HINT);\n }\n return undefined;\n}\n\n// ─── Tools ──────────────────────────────────────────────────────────────────\n\nconst directoryOverview: ToolDescriptor = {\n name: \"directory_overview\",\n title: \"Directory Overview\",\n description:\n \"The directory's vocabulary and scale in one call — call this FIRST when you need valid kits_search filter values or a map of what WorkerKit covers. Returns: kitCount (published kits right now); categories grouped as jobFamilies/roles/industries ({slug, name} — slugs feed the category/industry filters); apps ({code, name, categoryCode?, installable} — codes feed the app filter; installable:false means kits can show the app but an install cannot carry it); appCategories ({code, name, members:[{code, name, appCode}]} — codes feed the appCategory filter; members are what an installer picks between, e.g. Slack vs Teams); models ({model, normalized, kitCount} — pass normalized or any substring as the model filter); sortOptions; triggerModes. Vocabulary only — it lists no kits: for 'what is popular', use kits_search with the default downloads sort. Kit pages for humans follow https://workerkit.ai/kit/{slug}.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {},\n path: `${API}/overview`,\n annotations: READ_ONLY,\n};\n\nconst searchKits: ToolDescriptor = {\n name: \"kits_search\",\n title: \"Search Kits\",\n description:\n \"Search and browse the public WorkerKit kits directory. A kit is a pre-built AI worker template — a job instruction plus exact, pre-scoped app permissions (and often schedules) — that a human installs as a working AI worker in one click. All filters AND together; every value is optional (omit everything to browse the whole catalog). Returns {items, totalCount, page, pageSize}; each card: slug (the key for kit_get), name, jobSentence (what the worker does, one line), publisherName/publisherSlug/isOfficialPublisher/verificationTier, apps (app codes it uses) + categorySlots (capability slots where the installer picks the app, e.g. Slack vs Teams), categories, triggerModes, downloadCount, starCount, modelScores (publisher-declared 0-100 fit per model, best first) + recommendedModel, isProtected (publisher withholds the instruction TEXT; the kit still fully works — not a red flag), isFeatured, publishedAt. An empty result is not an error — see the footer it returns; valid category/app/appCategory/model filter values come from directory_overview. Kit page for humans: https://workerkit.ai/kit/{slug}.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n query: z.string().max(200).optional().describe(\n \"Free-text search: case-insensitive SUBSTRING match over kit name + job sentence — not keyword or semantic search, so one short stem ('invoice') beats a phrase ('help with my invoices'). Omit to browse by filters alone.\"\n ),\n category: z.string().optional().describe(\n \"Job-category slug (any kind — job family, role, or industry). Valid slugs: directory_overview → categories. Unknown slugs match nothing.\"\n ),\n industry: z.string().optional().describe(\n \"Industry-kind category slug ONLY (a role/job-family slug here matches nothing). ANDs with category.\"\n ),\n app: z.string().optional().describe(\n \"Exact app code the kit must use, e.g. 'email', 'slack', 'crm'. Valid codes: directory_overview → apps.\"\n ),\n appCategory: z.string().optional().describe(\n \"Capability-category code, e.g. 'team-collaboration': matches kits that define that install-time slot OR pin one of its member apps — broader than the app filter. Unknown codes error (the error names the fix). Valid codes: directory_overview → appCategories.\"\n ),\n model: z.string().max(80).optional().describe(\n \"Substring match on a scored model name, e.g. 'sonnet' or 'gpt'. Valid names: directory_overview → models.\"\n ),\n trigger: z.enum([\"onDemand\", \"scheduled\", \"event\"]).optional().describe(\n \"How the kit's worker runs: onDemand (a human or agent triggers it), scheduled (ships recurring schedules), event (webhook-triggered).\"\n ),\n publisher: z.string().optional().describe(\"Publisher slug (publisherSlug on any card) — that publisher's kits only.\"),\n sort: z.enum([\"downloads\", \"new\", \"name\", \"stars\"]).default(\"downloads\").describe(\n \"downloads = most installed (the popularity signal), new = latest published, name = A-Z, stars = most starred.\"\n ),\n page: z.number().int().min(1).default(1).describe(\"1-based page number.\"),\n pageSize: z.number().int().min(1).max(200).default(20).describe(\n \"Cards per page (max 200). 20 keeps responses lean; totalCount always reports the full match count.\"\n ),\n },\n path: `${API}/kits`,\n paramFilter: (params) => {\n // The wire param is `q`; `query` is the agent-facing name.\n const { query, ...rest } = params;\n return { ...rest, q: query };\n },\n annotations: READ_ONLY,\n mapData: (data) => kitListData(data),\n footer: (data) => listFooter(data as Json),\n};\n\nconst getKit: ToolDescriptor = {\n name: \"kit_get\",\n title: \"Get Kit\",\n description:\n \"One kit's full public dossier — everything a human (or an agent advising one) can evaluate before installing. Key fields: description + appDescriptions (author's per-app/per-tool notes); instructionContent — the worker's job instruction VERBATIM, the core of what you are evaluating (empty string when isProtected while instructionLength still reports the real size; startCommand/endCommand/whenToUse are null on a protected kit, deliberately indistinguishable from 'none'); permissionsManifest — the EXACT data access an install grants (per-app operations/fields/scopes; numeric value is authoritative, names/keys are display) — summarize THIS when asked what the kit can touch; requiredInputs + memorySetup — the install form: fields the kit needs and questions whose answers become the worker's memory; memoryProfile ('contextual' = the worker is shown its own recent runs) and selfFactsEnabled (the worker saves durable facts on its own); schedules/triggers/usageWindows; skillResources — reference docs the worker fetches on demand: key/kind/name always, plus description/contentLength on a non-protected kit (a protected kit lists identity only), body via includeResourceBodies; hasExternalMcpShells — TRUE means installing creates an MCP gateway in the installer's account pointing at the publisher's own upstream URL (permissionsManifest.mcpServers.shells) — surface this when recommending; scan — the security scan's result for the text being served: outcome 'cleared' or 'underReview' (BOTH are live, installable listings; 'underReview' means a check raised something a reviewer has not settled, never that the kit is unsafe), scannedAtUtc (null = published before the scanner existed, which is most of the catalog), checks — the check families that actually ran on THIS kit, so 'cleared' with only ['static'] is a weaker statement than 'cleared' with all three; and recommendation ('safe' | 'caution' | 'doNotInstall') — the SCANNER's own install advice about the content, which is independent of outcome (our moderation state) and may legitimately disagree with it, so attribute it to SkillSpector rather than to WorkerKit when you repeat it, and read 'caution' as 'worth a look', not as danger (the scanner also emits it when its own analysis was incomplete); scan is absent for a kit with nothing to report, and it never carries the findings themselves; modelScores (with notes), downloadCount/starCount, and pageUrl — the install page to hand to the human. 404 = no published kit with that slug.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(SLUG_HINT),\n includeResourceBodies: z.boolean().default(false).describe(\n \"true = include each skill resource's full text (can be up to 20k chars each). Default false returns key/kind/name/description/contentLength — enough to describe the kit; fetch bodies only when their content is the question.\"\n ),\n },\n path: (params) => `${API}/kits/${encodeURIComponent(String(params.slug))}`,\n paramFilter: (params) => {\n const { slug: _slug, ...queryParams } = params;\n return queryParams;\n },\n annotations: READ_ONLY,\n mapData: kitDetailData,\n footer: kitDetailFooter,\n};\n\nconst getKitStats: ToolDescriptor = {\n name: \"kit_stats\",\n title: \"Get Kit Stats\",\n description:\n \"One kit's adoption over time: downloadCount (lifetime installs), dailyTrend (per-day installs over the trailing 30 days, UTC — sparse, omitted days are 0), lifetimeTrend (the whole history in at most 52 Monday-aligned buckets; buckets widen for older kits; counts sum to downloadCount). Use it to compare traction between shortlisted kits or to tell 'popular lately' from 'popular once' — the cards' downloadCount alone cannot.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(SLUG_HINT),\n },\n path: (params) => `${API}/kits/${encodeURIComponent(String(params.slug))}/stats`,\n paramFilter: () => ({}),\n annotations: READ_ONLY,\n};\n\nconst getPublisher: ToolDescriptor = {\n name: \"publisher_get\",\n title: \"Get Publisher\",\n description:\n \"A kit publisher's public profile + their published kits — the 'who is behind this?' trust check. Returns {publisher, kits, pageUrl}: publisher has name, isOfficial (published by WorkerKit itself), verification handles (xHandle → x.com/{handle}, gitHubHandle → github.com/{handle}, linkedInUrl), description, createDate (member since), kitCount and totalDownloads (published kits only); kits is the same paginated card list kits_search returns, scoped to this publisher. 404 = unknown slug OR a publisher with nothing currently published.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(\"The publisher's slug, as returned on any kit card (publisherSlug).\"),\n sort: z.enum([\"downloads\", \"new\", \"name\", \"stars\"]).default(\"downloads\").describe(\"Sort for the publisher's kit list.\"),\n page: z.number().int().min(1).default(1).describe(\"1-based page of the publisher's kit list.\"),\n pageSize: z.number().int().min(1).max(200).default(20).describe(\"Kits per page (max 200).\"),\n },\n path: (params) => `${API}/publishers/${encodeURIComponent(String(params.slug))}`,\n paramFilter: (params) => {\n const { slug: _slug, ...queryParams } = params;\n return queryParams;\n },\n annotations: READ_ONLY,\n mapData: publisherPageData,\n footer: (data) => publisherPageFooter(data),\n};\n\n// ─── Authoring reads ────────────────────────────────────────────────────────\n\nconst GUIDE_SECTIONS = [\"index\", \"schema\", \"rules\", \"skill\", \"slots\", \"instruction\", \"example\", \"selfcheck\"] as const;\n\nconst kitAuthoringGuide: ToolDescriptor = {\n name: \"kit_authoring_guide\",\n title: \"Kit Authoring Guide\",\n description:\n \"The guide for WRITING a kit, one section at a time — read it before authoring anything for kit_validate / kit_publish. Sections: index (start here: what a kit is, the flow, where the vocabulary lives — the default), schema (the publish payload, every field with its cap, and what the server sets for you), rules (every rule that fails a publish), skill (the instruction, the three when-fields, skill resources, errors, the three label kinds and how they resolve), slots (pin an app vs offer a capability slot; how vendor tiles map onto content), instruction (the instruction skeleton the structure lint nudges toward — also the shape for instruction_set), example (a complete, valid kit), selfcheck (the list to run before publishing). Returns {section, title, content (markdown), sections[] (key, title, chars — the table of contents), vocabularyHint}. The guide carries NO app codes, tool keys or category slugs on purpose — they change with every provider shipped — read those live with kit_vocabulary. Read index first, then schema; page the rest as you need it rather than reading all eight in one turn.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n section: z.enum(GUIDE_SECTIONS).default(\"index\").describe(\n \"Which section to read. index (default) is the table of contents plus how to use the guide; schema and rules are the two an author cannot skip.\"\n ),\n },\n path: `${API}/authoring/guide`,\n annotations: READ_ONLY,\n};\n\nconst kitVocabulary: ToolDescriptor = {\n name: \"kit_vocabulary\",\n title: \"Kit Authoring Vocabulary\",\n description:\n \"The live vocabulary a kit's permission manifest accepts — read it before writing content.apps / content.categorySlots / categorySlugs, because every key is validated strictly and there is no 'all' shorthand. Without app: everything except per-app tools — apps[] (per surface: code, name, summary, operations = the tool KEYS you grant, fields, and every axis it supports: readOperations, masterAccessLevels, writableFields, providers, channels, objectTypes, scopePolicies, contentTypeScopes, capabilities, supportsAllowAll, supportsWriteEnabled, subApps, installable), concreteApps[] (vendor tiles like Gmail, Monday, Google Sheets with kind standalone|provider|slotMember|subApp — how each lands in content), appCategories[] (the capability slots with members, labelAlias, genericName), categories {jobFamilies, roles, industries} (the ONLY valid categorySlugs), models[], mcpApps[] (platform MCP apps a kit may bind via content.mcpServers — id is the gatewayId, tools[].toolId the toolIds; an account's OWN servers are on the /workers mount's mcp_servers_list instead), and note. With app=<code>: that ONE surface as {app, vendors, tools, note} where tools are what an installed worker sees on it — each {name (cite this in the instruction), description, readOnly, requires (grant at least one of these keys under operations to get the tool)}; toolsNote replaces tools on a surface no catalog covers. The full read is large: take it once per authoring task, then per-app reads for the surfaces you use. To explore what every app can do before choosing, kit_app_tools is the one-call view. An unknown app is a 400 naming every valid code.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n app: z.string().max(40).optional().describe(\n \"One app code (from apps[].code) to read just that surface with its vendors and tools. Omit for the whole vocabulary.\"\n ),\n },\n path: `${API}/authoring/vocabulary`,\n annotations: READ_ONLY,\n};\n\nconst kitAppTools: ToolDescriptor = {\n name: \"kit_app_tools\",\n title: \"Kit App Tools\",\n description:\n \"What a worker can actually DO, app by app — the explorer to read when deciding which apps a kit needs. Returns apps[] in catalog order, each {app (the code content.apps[].code takes), name, summary, operations (the app's key vocabulary), tools[]} where every tool is {name, title, description (the base text the worker's model is handed), readOnly (false = it changes data on the connected app), requires (the operation keys of which AT LEAST ONE must be in that app's content.apps[].operations for the tool to appear — absent means the tool comes with the app), provider (vendor-pinned tools in a multi-vendor family), scope (drive content family), hosted (present as false only for a tool served to MCP clients but never to a hosted worker run)}; a surface no catalog covers carries toolsNote instead of tools. toolCount totals the catalog; note states the unlock rule. app=<code> narrows to one app (unknown = 400 naming every valid code). Platform MCP apps and their tools are on kit_vocabulary (mcpApps); an app that is in neither can be added as the account's own custom MCP app (mcp_server_create on the /workers mount — the customMcp entry's toolsNote says how). Around 300 tools in the full read — take it once, then kit_vocabulary for the axes of the apps you pick.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n app: z.string().max(40).optional().describe(\n \"One app code to read just that app's tools. Omit for every app.\"\n ),\n },\n path: `${API}/authoring/tools`,\n annotations: READ_ONLY,\n};\n\n// ─── About ──────────────────────────────────────────────────────────────────\n//\n// The one read that is not about kits: what WorkerKit is and when an agent\n// should reach for it, written for the agent. First in the registry on purpose:\n// a model reads tools/list top-down, and this is the tool that tells it whether\n// the rest of the list applies to the request in front of it.\n\nconst ABOUT_SECTIONS = [\"index\", \"why\", \"operate\", \"access\", \"cost\", \"start\"] as const;\n\nconst workerkitAbout: ToolDescriptor = {\n name: \"workerkit_about\",\n title: \"About WorkerKit\",\n description:\n \"What WorkerKit is and when to use it, written for an agent. Read this FIRST when a user asks for recurring, scheduled, background, monitoring, triage, or per-client work, or asks what WorkerKit can do, and before recommending or dismissing a worker for a job. One section at a time: index (default: what WorkerKit is in one read, the request shapes that call for a worker, the sections, the first three calls), why (the problem a worker solves, what a worker is made of, what it unlocks), operate (how you run a fleet: key_info first, runs_feed and fleet_pulse to watch, receipts, two-way runs, changing a worker, the rules that are not obvious), access (what a worker can reach, how narrow a grant can be, the firewall on every call, what a key cannot do), cost (priced to the token, what is never billed, how budgets refuse, plans and wallet), start (how to connect from an MCP host, a REST host or a terminal, and what to tell your user). Returns {section, title, content (markdown), sections[] (key, title, chars: the table of contents), hint}. The text inlines no number and no vocabulary that lives elsewhere: prices are on workerkit.ai/pricing.md, apps and their tools on directory_overview and kit_app_tools, a key's scopes on key_info. Read index, then why and start; page the rest as the task needs it. When no published kit fits a job, the text says to author one (kit_authoring_guide, then kit_validate, kit_publish private, kit_install) rather than install a near miss.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n section: z.enum(ABOUT_SECTIONS).default(\"index\").describe(\n \"Which section to read. index (default) is the one-read summary plus the table of contents; why and start are the two to read before recommending WorkerKit to a user.\"\n ),\n },\n path: `${API}/about`,\n annotations: READ_ONLY,\n};\n\n// ─── Registry ───────────────────────────────────────────────────────────────\n\nexport const directoryDescriptors: readonly ToolDescriptor[] = [\n workerkitAbout,\n directoryOverview,\n searchKits,\n getKit,\n getKitStats,\n getPublisher,\n kitAuthoringGuide,\n kitVocabulary,\n kitAppTools,\n];\n"]}
1
+ {"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/descriptors/directory.ts"],"names":[],"mappings":"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","sourcesContent":["// The public kits-directory tools: anonymous, read-only catalog tools over the\n// public directory API. Nine tools rather than one per REST endpoint — the about read\n// (what WorkerKit is and when an agent should reach for it), one vocabulary\n// call, one search, one dossier, one stats read, one publisher profile, and the\n// three authoring reads (the guide, the permission vocabulary an author needs,\n// and the explorer of what each app lets a worker do).\n//\n// The upstream surface is already agent-shaped (always-anonymous, no\n// viewer-scoped fields, opt-in skill-resource bodies, composed overview), so\n// these tools stay thin passthroughs. What lives HERE is the pure half of the\n// presentation an MCP server (or CLI) should not each reinvent:\n// - Empty search results append a broaden-this hint; truncated results append\n// the next page number — the two places agents reliably mis-step.\n// - kit_get / publisher_get carry a computed pageUrl: nothing on an anonymous\n// surface can install, so the agent hands over the link — or, when it holds\n// a manager key with the installKits scope, installs via kit_install_preview\n// / kit_install on the authenticated WorkerKit Manager server.\n\nimport { z } from \"../zod.js\";\nimport { READ_ONLY, type ToolDescriptor } from \"./types.js\";\n\nconst API = \"/api/directory/mcp\";\nconst SITE = \"https://workerkit.ai\";\n\n// ─── Shared phrasing ────────────────────────────────────────────────────────\n\nconst SLUG_HINT = \"The kit's URL slug, as returned by kits_search (slug).\";\n\n// Appended to every tool: the two facts an agent must never get wrong on a\n// public mount — no auth exists, and installing is out of its reach.\nconst DIRECTORY_NOTE =\n \" Public and anonymous: results are identical for everyone, and nothing here installs or publishes. Install: a signed-in human on the kit's workerkit.ai page (offer the URL), or an agent with the installKits scope via kit_install_preview / kit_install on the WorkerKit Manager mount (/workers). Author: kit_authoring_guide + kit_vocabulary here, then kit_validate / kit_publish on /workers (publishKits scope).\";\n\n// The two authoring reads share one framing: they are what an agent reads BEFORE\n// writing a kit for the manager surface, and they are anonymous so it can draft\n// before it holds any credential.\nconst AUTHORING_NOTE =\n \" Public and anonymous, identical for everyone. The kit is validated and published on the WorkerKit Manager mount (/workers): kit_validate (every section's verdict at once), then kit_publish — publishKits scope. Publish PRIVATE first (visibility 'private'): a private kit installs only on its own account (a signed-in human on its workerkit.ai page, or an agent via kit_install), which is also how a worker is created from scratch. A worker uses only apps CONNECTED on its operator (apps_list; app_connect for credential-based ones). An app the platform lacks is added as the account's own custom MCP app: mcp_server_create (credential included), mcp_server_set_tools, then content.mcpServers in the kit.\";\n\n// ─── Pure data mappers + footers (presentation data, not ToolResult assembly) ─\n\ntype Json = Record<string, unknown>;\n\nconst SEARCH_EMPTY_HINT =\n \"No kits matched. Filters AND together — drop some. query is a plain case-insensitive substring over name + job sentence (one short word beats a phrase), and unknown category/app/publisher values match nothing rather than erroring. directory_overview lists every valid filter value. If nothing fits after broadening, author a kit for the exact job rather than installing a near miss: kit_authoring_guide (index, then schema and rules) and kit_app_tools here, then kit_validate and kit_publish (private) on the /workers mount, then kit_install.\";\n\n// publisher_get accepts no search filters, so the search hint above would tell an\n// agent to broaden filters it never set. Reachable: the profile 404s only when the\n// publisher has no PUBLISHED kits, while the catalog list additionally excludes\n// taken-down ones — so a publisher whose only published kit was moderated out\n// returns 200 with an empty items array.\nconst PUBLISHER_EMPTY_HINT =\n \"This publisher currently lists no kits (publisher.kitCount can still be non-zero — a published kit can be withheld from the catalog). publisher_get takes no search filters, so there is nothing to broaden; report the profile as-is.\";\n\n/**\n * The one footer a {items, totalCount, page, pageSize} list needs: how to\n * broaden when nothing matched, or which page comes next when truncated.\n */\nexport function listFooter(body: Json, emptyHint: string = SEARCH_EMPTY_HINT): string | undefined {\n const items = Array.isArray(body.items) ? body.items : [];\n const totalCount = typeof body.totalCount === \"number\" ? body.totalCount : items.length;\n const page = typeof body.page === \"number\" ? body.page : 1;\n const pageSize = typeof body.pageSize === \"number\" && body.pageSize > 0 ? body.pageSize : Math.max(items.length, 1);\n if (totalCount === 0) {\n return emptyHint;\n }\n if (page * pageSize < totalCount) {\n return `Showing page ${page} of ${Math.ceil(totalCount / pageSize)} (${totalCount} kits total) — call again with page: ${page + 1} for more`;\n }\n return undefined;\n}\n\n/** kits_search data: the validated list body, or undefined = serve verbatim. */\nexport function kitListData(data: unknown): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || !Array.isArray((body as Json).items)) {\n return undefined; // unexpected shape — serve verbatim rather than guess\n }\n return body;\n}\n\n/** kit_get data: the dossier with the computed pageUrl, or undefined = verbatim. */\nexport function kitDetailData(data: unknown, params: Record<string, unknown>): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return undefined;\n\n const detail = { ...body };\n const slug = typeof detail.slug === \"string\" && detail.slug.length > 0 ? detail.slug : String(params.slug ?? \"\");\n detail.pageUrl = `${SITE}/kit/${encodeURIComponent(slug)}`;\n return detail;\n}\n\n/**\n * kit_get footer. Bodies exist upstream but were not requested: each such\n * resource reports a contentLength with no content. A protected kit's resources\n * carry neither (identity-only), so this stays silent there — re-calling would\n * not help.\n */\nexport function kitDetailFooter(data: unknown, params: Record<string, unknown>): string | undefined {\n const detail = data as Json;\n if (params.includeResourceBodies !== true && Array.isArray(detail.skillResources)) {\n const omitted = detail.skillResources.filter(\n (r) =>\n r !== null && typeof r === \"object\" && !Array.isArray(r) &&\n typeof (r as Json).contentLength === \"number\" && ((r as Json).contentLength as number) > 0 &&\n typeof (r as Json).content !== \"string\"\n ).length;\n if (omitted > 0) {\n return `${omitted} skillResources ${omitted === 1 ? \"body\" : \"bodies\"} omitted — call again with includeResourceBodies: true to read them`;\n }\n }\n return undefined;\n}\n\n/** publisher_get data: the profile with the computed pageUrl, or undefined = verbatim. */\nexport function publisherPageData(data: unknown, params: Record<string, unknown>): Json | undefined {\n const body = data as Json | null;\n if (!body || typeof body !== \"object\" || Array.isArray(body)) return undefined;\n\n const page = { ...body };\n const publisher = page.publisher as Json | undefined;\n const slug =\n publisher && typeof publisher.slug === \"string\" && publisher.slug.length > 0\n ? publisher.slug\n : String(params.slug ?? \"\");\n page.pageUrl = `${SITE}/publishers/${encodeURIComponent(slug)}`;\n return page;\n}\n\n/** publisher_get footer: pages the embedded kit list with the publisher-shaped empty hint. */\nexport function publisherPageFooter(data: unknown): string | undefined {\n const page = data as Json;\n const kits = page.kits;\n if (kits && typeof kits === \"object\" && !Array.isArray(kits) && Array.isArray((kits as Json).items)) {\n return listFooter(kits as Json, PUBLISHER_EMPTY_HINT);\n }\n return undefined;\n}\n\n// ─── Tools ──────────────────────────────────────────────────────────────────\n\nconst directoryOverview: ToolDescriptor = {\n name: \"directory_overview\",\n title: \"Directory Overview\",\n description:\n \"The directory's vocabulary and scale in one call — call this FIRST when you need valid kits_search filter values or a map of what WorkerKit covers. Returns: kitCount (published kits right now); categories grouped as jobFamilies/roles/industries ({slug, name} — slugs feed the category/industry filters); apps ({code, name, categoryCode?, installable} — codes feed the app filter; installable:false means kits can show the app but an install cannot carry it); appCategories ({code, name, members:[{code, name, appCode}]} — codes feed the appCategory filter; members are what an installer picks between, e.g. Slack vs Teams); models ({model, normalized, kitCount} — pass normalized or any substring as the model filter); modelTypes ({code, name, summary} — 'language' | 'decision', each with its one-line summary; codes feed the modelType filter); sortOptions; triggerModes. Vocabulary only — it lists no kits: for 'what is popular', use kits_search with the default downloads sort. Kit pages for humans follow https://workerkit.ai/kit/{slug}.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {},\n path: `${API}/overview`,\n annotations: READ_ONLY,\n};\n\nconst searchKits: ToolDescriptor = {\n name: \"kits_search\",\n title: \"Search Kits\",\n description:\n \"Search and browse the public WorkerKit kits directory. A kit is a pre-built AI worker template — a job instruction plus exact, pre-scoped app permissions (and often schedules) — that a human installs as a working AI worker in one click. All filters AND together; every value is optional (omit everything to browse the whole catalog). Returns {items, totalCount, page, pageSize}; each card: slug (the key for kit_get), name, jobSentence (what the worker does, one line), publisherName/publisherSlug/isOfficialPublisher/verificationTier, apps (app codes it uses) + categorySlots (capability slots where the installer picks the app, e.g. Slack vs Teams), categories, triggerModes, downloadCount, starCount, modelScores (publisher-declared 0-100 fit per model, best first) + recommendedModel, modelType ('language' | 'decision' — see the filter), isProtected (publisher withholds the instruction TEXT; the kit still fully works — not a red flag), isFeatured, publishedAt. An empty result is not an error — see the footer it returns; valid category/app/appCategory/model filter values come from directory_overview. Kit page for humans: https://workerkit.ai/kit/{slug}.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n query: z.string().max(200).optional().describe(\n \"Free-text search: case-insensitive SUBSTRING match over kit name + job sentence — not keyword or semantic search, so one short stem ('invoice') beats a phrase ('help with my invoices'). Omit to browse by filters alone.\"\n ),\n category: z.string().optional().describe(\n \"Job-category slug (any kind — job family, role, or industry). Valid slugs: directory_overview → categories. Unknown slugs match nothing.\"\n ),\n industry: z.string().optional().describe(\n \"Industry-kind category slug ONLY (a role/job-family slug here matches nothing). ANDs with category.\"\n ),\n app: z.string().optional().describe(\n \"Exact app code the kit must use, e.g. 'email', 'slack', 'crm'. Valid codes: directory_overview → apps.\"\n ),\n appCategory: z.string().optional().describe(\n \"Capability-category code, e.g. 'team-collaboration': matches kits that define that install-time slot OR pin one of its member apps — broader than the app filter. Unknown codes error (the error names the fix). Valid codes: directory_overview → appCategories.\"\n ),\n model: z.string().max(80).optional().describe(\n \"Substring match on a scored model name, e.g. 'sonnet' or 'gpt'. Valid names: directory_overview → models.\"\n ),\n trigger: z.enum([\"onDemand\", \"scheduled\", \"event\"]).optional().describe(\n \"How the kit's worker runs: onDemand (a human or agent triggers it), scheduled (ships recurring schedules), event (webhook-triggered).\"\n ),\n modelType: z.enum([\"language\", \"decision\"]).optional().describe(\n \"language = an instruction the installer runs on a model of their choice; decision = a routing table the decision model applies per item (triage, sorting, labelling, filtering — no instruction, no model to pick). Omit for both.\"\n ),\n publisher: z.string().optional().describe(\"Publisher slug (publisherSlug on any card) — that publisher's kits only.\"),\n sort: z.enum([\"downloads\", \"new\", \"name\", \"stars\"]).default(\"downloads\").describe(\n \"downloads = most installed (the popularity signal), new = latest published, name = A-Z, stars = most starred.\"\n ),\n page: z.number().int().min(1).default(1).describe(\"1-based page number.\"),\n pageSize: z.number().int().min(1).max(200).default(20).describe(\n \"Cards per page (max 200). 20 keeps responses lean; totalCount always reports the full match count.\"\n ),\n },\n path: `${API}/kits`,\n paramFilter: (params) => {\n // The wire param is `q`; `query` is the agent-facing name.\n const { query, ...rest } = params;\n return { ...rest, q: query };\n },\n annotations: READ_ONLY,\n mapData: (data) => kitListData(data),\n footer: (data) => listFooter(data as Json),\n};\n\nconst getKit: ToolDescriptor = {\n name: \"kit_get\",\n title: \"Get Kit\",\n description:\n \"One kit's full public dossier — what a human, or an agent advising one, evaluates before installing. Fields: description + appDescriptions (the author's per-app / per-tool notes); modelType ('language', the default, or 'decision'); instructionContent — a language kit's job instruction VERBATIM, the core of what you are evaluating (empty when isProtected, with instructionLength still real; startCommand / endCommand / whenToUse are null on a protected kit, indistinguishable from 'none'); on a DECISION kit evaluate decisionNarration instead (what it reads, the questions it asks each item, the rules that route them, what happens below the confidence floor — served on protected kits too) and decisionSetup (the questions its installer answers); permissionsManifest — the EXACT data access an install grants (per-app operations / fields / scopes; the numeric value is authoritative, names are display) — summarize THIS when asked what the kit can touch; requiredInputs + memorySetup — the install form (fields the kit needs, questions whose answers become the worker's memory); memoryProfile ('contextual' = the worker sees its own recent runs) and selfFactsEnabled (it saves durable facts on its own); schedules / triggers / usageWindows; skillResources — reference docs the worker fetches on demand (key / kind / name always; description / contentLength unless protected; bodies via includeResourceBodies); hasExternalMcpShells — TRUE means installing creates an MCP gateway in the installer's account pointing at the publisher's own upstream URL (permissionsManifest.mcpServers.shells): surface it when recommending; scan — the security scan of the text being served: outcome 'cleared' or 'underReview' (both are live, installable listings — 'underReview' means a reviewer has not settled a raised check, never that the kit is unsafe), scannedAtUtc (null = published before the scanner existed, most of the catalog), checks (the families that ran on THIS kit — 'cleared' on ['static'] alone is weaker than on all three) and recommendation ('safe' | 'caution' | 'doNotInstall', the SCANNER's own advice, independent of outcome and possibly disagreeing with it: attribute it to SkillSpector, and read 'caution' as 'worth a look' — it is also emitted when the analysis was incomplete); scan is absent when there is nothing to report and never carries findings; modelScores (with notes), downloadCount / starCount, and pageUrl — the install page to hand to the human. 404 = no published kit with that slug.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(SLUG_HINT),\n includeResourceBodies: z.boolean().default(false).describe(\n \"true = include each skill resource's full text (can be up to 20k chars each). Default false returns key/kind/name/description/contentLength — enough to describe the kit; fetch bodies only when their content is the question.\"\n ),\n },\n path: (params) => `${API}/kits/${encodeURIComponent(String(params.slug))}`,\n paramFilter: (params) => {\n const { slug: _slug, ...queryParams } = params;\n return queryParams;\n },\n annotations: READ_ONLY,\n mapData: kitDetailData,\n footer: kitDetailFooter,\n};\n\nconst getKitStats: ToolDescriptor = {\n name: \"kit_stats\",\n title: \"Get Kit Stats\",\n description:\n \"One kit's adoption over time: downloadCount (lifetime installs), dailyTrend (per-day installs over the trailing 30 days, UTC — sparse, omitted days are 0), lifetimeTrend (the whole history in at most 52 Monday-aligned buckets; buckets widen for older kits; counts sum to downloadCount). Use it to compare traction between shortlisted kits or to tell 'popular lately' from 'popular once' — the cards' downloadCount alone cannot.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(SLUG_HINT),\n },\n path: (params) => `${API}/kits/${encodeURIComponent(String(params.slug))}/stats`,\n paramFilter: () => ({}),\n annotations: READ_ONLY,\n};\n\nconst getPublisher: ToolDescriptor = {\n name: \"publisher_get\",\n title: \"Get Publisher\",\n description:\n \"A kit publisher's public profile + their published kits — the 'who is behind this?' trust check. Returns {publisher, kits, pageUrl}: publisher has name, isOfficial (published by WorkerKit itself), verification handles (xHandle → x.com/{handle}, gitHubHandle → github.com/{handle}, linkedInUrl), description, createDate (member since), kitCount and totalDownloads (published kits only); kits is the same paginated card list kits_search returns, scoped to this publisher. 404 = unknown slug OR a publisher with nothing currently published.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n slug: z.string().min(1).describe(\"The publisher's slug, as returned on any kit card (publisherSlug).\"),\n sort: z.enum([\"downloads\", \"new\", \"name\", \"stars\"]).default(\"downloads\").describe(\"Sort for the publisher's kit list.\"),\n page: z.number().int().min(1).default(1).describe(\"1-based page of the publisher's kit list.\"),\n pageSize: z.number().int().min(1).max(200).default(20).describe(\"Kits per page (max 200).\"),\n },\n path: (params) => `${API}/publishers/${encodeURIComponent(String(params.slug))}`,\n paramFilter: (params) => {\n const { slug: _slug, ...queryParams } = params;\n return queryParams;\n },\n annotations: READ_ONLY,\n mapData: publisherPageData,\n footer: (data) => publisherPageFooter(data),\n};\n\n// ─── Authoring reads ────────────────────────────────────────────────────────\n\nconst GUIDE_SECTIONS = [\"index\", \"schema\", \"rules\", \"skill\", \"slots\", \"instruction\", \"example\", \"selfcheck\"] as const;\n\nconst kitAuthoringGuide: ToolDescriptor = {\n name: \"kit_authoring_guide\",\n title: \"Kit Authoring Guide\",\n description:\n \"The guide for WRITING a kit, one section at a time — read it before authoring anything for kit_validate / kit_publish. Sections: index (start here: what a kit is, the flow, where the vocabulary lives — the default), schema (the publish payload, every field with its cap, and what the server sets for you), rules (every rule that fails a publish), skill (the instruction, the three when-fields, skill resources, errors, the three label kinds and how they resolve), slots (pin an app vs offer a capability slot; how vendor tiles map onto content), instruction (the instruction skeleton the structure lint nudges toward — also the shape for instruction_set), example (a complete, valid kit), selfcheck (the list to run before publishing). Returns {section, title, content (markdown), sections[] (key, title, chars — the table of contents), vocabularyHint}. The guide carries NO app codes, tool keys or category slugs on purpose — they change with every provider shipped — read those live with kit_vocabulary. Read index first, then schema; page the rest as you need it rather than reading all eight in one turn.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n section: z.enum(GUIDE_SECTIONS).default(\"index\").describe(\n \"Which section to read. index (default) is the table of contents plus how to use the guide; schema and rules are the two an author cannot skip.\"\n ),\n },\n path: `${API}/authoring/guide`,\n annotations: READ_ONLY,\n};\n\nconst kitVocabulary: ToolDescriptor = {\n name: \"kit_vocabulary\",\n title: \"Kit Authoring Vocabulary\",\n description:\n \"The live vocabulary a kit's permission manifest accepts — read it before writing content.apps / content.categorySlots / categorySlugs: every key is validated strictly and there is no 'all' shorthand. Without app: apps[] (per surface: code, name, summary, operations = the tool KEYS you grant, fields, and every axis it supports — readOperations, masterAccessLevels, writableFields, providers, channels, objectTypes, scopePolicies, contentTypeScopes, capabilities, supportsAllowAll, supportsWriteEnabled, subApps, installable), concreteApps[] (vendor tiles such as Gmail, Monday or Google Sheets, kind standalone | provider | slotMember | subApp — how each lands in content), appCategories[] (the capability slots: members, labelAlias, genericName), categories {jobFamilies, roles, industries} (the ONLY valid categorySlugs), models[], mcpApps[] (platform MCP apps a kit binds via content.mcpServers — id is the gatewayId, tools[].toolId the toolIds; the account's OWN servers are mcp_servers_list on /workers) and note. With app=<code>: that ONE surface as {app, vendors, tools, note}, tools being what an installed worker sees — each {name (cite it in the instruction), description, readOnly, requires (grant one of these keys under operations to get the tool)}; toolsNote replaces tools where no catalog covers the surface. The full read is large: take it once per authoring task, then per-app reads for the surfaces you use; kit_app_tools is the one-call view of what every app can do. Unknown app = 400 naming every valid code.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n app: z.string().max(40).optional().describe(\n \"One app code (from apps[].code) to read just that surface with its vendors and tools. Omit for the whole vocabulary.\"\n ),\n },\n path: `${API}/authoring/vocabulary`,\n annotations: READ_ONLY,\n};\n\nconst kitAppTools: ToolDescriptor = {\n name: \"kit_app_tools\",\n title: \"Kit App Tools\",\n description:\n \"What a worker can actually DO, app by app — the explorer to read when deciding which apps a kit needs. Returns apps[] in catalog order, each {app (the code content.apps[].code takes), name, summary, operations (the app's key vocabulary), tools[]} where every tool is {name, title, description (the base text the worker's model is handed), readOnly (false = it changes data on the connected app), requires (the operation keys of which AT LEAST ONE must be in that app's content.apps[].operations for the tool to appear — absent means the tool comes with the app), provider (vendor-pinned tools in a multi-vendor family), scope (drive content family), hosted (present as false only for a tool served to MCP clients but never to a hosted worker run)}; a surface no catalog covers carries toolsNote instead of tools. toolCount totals the catalog; note states the unlock rule. app=<code> narrows to one app (unknown = 400 naming every valid code). Platform MCP apps and their tools are on kit_vocabulary (mcpApps); an app that is in neither can be added as the account's own custom MCP app (mcp_server_create on the /workers mount — the customMcp entry's toolsNote says how). Around 300 tools in the full read — take it once, then kit_vocabulary for the axes of the apps you pick.\" +\n AUTHORING_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n app: z.string().max(40).optional().describe(\n \"One app code to read just that app's tools. Omit for every app.\"\n ),\n },\n path: `${API}/authoring/tools`,\n annotations: READ_ONLY,\n};\n\n// ─── About ──────────────────────────────────────────────────────────────────\n//\n// The one read that is not about kits: what WorkerKit is and when an agent\n// should reach for it, written for the agent. First in the registry on purpose:\n// a model reads tools/list top-down, and this is the tool that tells it whether\n// the rest of the list applies to the request in front of it.\n\nconst ABOUT_SECTIONS = [\"index\", \"why\", \"operate\", \"access\", \"cost\", \"start\"] as const;\n\nconst workerkitAbout: ToolDescriptor = {\n name: \"workerkit_about\",\n title: \"About WorkerKit\",\n description:\n \"What WorkerKit is and when to use it, written for an agent. Read this FIRST when a user asks for recurring, scheduled, background, monitoring, triage, or per-client work, or asks what WorkerKit can do, and before recommending or dismissing a worker for a job. One section at a time: index (default: what WorkerKit is in one read, the request shapes that call for a worker, the sections, the first three calls), why (the problem a worker solves, what a worker is made of, what it unlocks), operate (how you run a fleet: key_info first, runs_feed and fleet_pulse to watch, receipts, two-way runs, changing a worker, the rules that are not obvious), access (what a worker can reach, how narrow a grant can be, the firewall on every call, what a key cannot do), cost (priced to the token, what is never billed, how budgets refuse, plans and wallet), start (how to connect from an MCP host, a REST host or a terminal, and what to tell your user). Returns {section, title, content (markdown), sections[] (key, title, chars: the table of contents), hint}. The text inlines no number and no vocabulary that lives elsewhere: prices are on workerkit.ai/pricing.md, apps and their tools on directory_overview and kit_app_tools, a key's scopes on key_info. Read index, then why and start; page the rest as the task needs it. When no published kit fits a job, the text says to author one (kit_authoring_guide, then kit_validate, kit_publish private, kit_install) rather than install a near miss.\" +\n DIRECTORY_NOTE,\n auth: \"anonymous\",\n method: \"get\",\n schema: {\n section: z.enum(ABOUT_SECTIONS).default(\"index\").describe(\n \"Which section to read. index (default) is the one-read summary plus the table of contents; why and start are the two to read before recommending WorkerKit to a user.\"\n ),\n },\n path: `${API}/about`,\n annotations: READ_ONLY,\n};\n\n// ─── Registry ───────────────────────────────────────────────────────────────\n\nexport const directoryDescriptors: readonly ToolDescriptor[] = [\n workerkitAbout,\n directoryOverview,\n searchKits,\n getKit,\n getKitStats,\n getPublisher,\n kitAuthoringGuide,\n kitVocabulary,\n kitAppTools,\n];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/descriptors/manage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAi7D7F,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAgFtD,CAAC"}
1
+ {"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../../src/descriptors/manage.ts"],"names":[],"mappings":"AAMA,OAAO,EAA8C,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AA69D7F,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAgFtD,CAAC"}