@workerkit/core 0.3.8 → 0.3.9

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,17 @@ and the package adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.9] - 2026-10-06
10
+
11
+ ### Added
12
+
13
+ - `kit_install` accepts `githubSelection`: the GitHub accounts a new worker may use, each with all of its repositories or 1-500 selected repository IDs. Selections are validated before the request, and an empty account list is sent as-is to leave GitHub setup for later. `kit_install_preview` lists the connected accounts in `githubAccounts`.
14
+
15
+ ### Changed
16
+
17
+ - `onboarding_get` documents how the spend policy counts settled cost, BYOK fees and active reservations, when its daily and monthly windows reset, and how a refusal at the human-approved ceiling differs from the fleet budget.
18
+ - `app_connect` and `app_disconnect` list `nimble` among the credential providers.
19
+
9
20
  ## [0.3.8] - 2026-09-29
10
21
 
11
22
  ### Added
@@ -1,4 +1,4 @@
1
- // The 79 authenticated fleet-management tools, as pure descriptors. The
1
+ // The 85 authenticated fleet-management tools, as pure descriptors. The
2
2
  // descriptions ARE the product surface: they are served verbatim to MCP
3
3
  // clients (and any future CLI help), so every contract nuance an agent must
4
4
  // not get wrong is taught here.
@@ -790,10 +790,28 @@ const KIT_SLUG_HINT = "The kit's slug, as returned by kits_search / kit_get on t
790
790
  // an unpinned slug could walk the request off /api/manage/kits before it ever leaves this
791
791
  // process. No real slug can contain a dot, so nothing legitimate is refused.
792
792
  const KIT_SLUG = z.string().min(1).max(120).regex(/^[a-z0-9][a-z0-9-]*$/, "not a valid kit slug");
793
+ // The backend's GitHub selection rules, checked before the request: up to 20 distinct
794
+ // accounts, each granting every repository ("all") or 1-500 distinct repository IDs
795
+ // ("selected"). An empty account list is a deliberate choice and is sent as-is.
796
+ const GITHUB_ACCOUNT_SELECTION = z.object({
797
+ connectionId: z.number().int().positive(),
798
+ repositoryMode: z.enum(["all", "selected"]),
799
+ repositoryIds: z.array(z.number().int().positive()).max(500).default([]),
800
+ }).superRefine((account, ctx) => {
801
+ if (account.repositoryMode === "selected" && account.repositoryIds.length === 0)
802
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["repositoryIds"], message: "Select at least one repository." });
803
+ if (account.repositoryMode === "all" && account.repositoryIds.length !== 0)
804
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["repositoryIds"], message: "All repositories mode must not include a repository list." });
805
+ if (new Set(account.repositoryIds).size !== account.repositoryIds.length)
806
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["repositoryIds"], message: "Repository IDs must be distinct." });
807
+ });
808
+ const GITHUB_SELECTION = z.object({
809
+ accounts: z.array(GITHUB_ACCOUNT_SELECTION).max(20),
810
+ }).refine((selection) => new Set(selection.accounts.map((a) => a.connectionId)).size === selection.accounts.length, "GitHub accounts must be distinct.");
793
811
  const kitInstallPreview = {
794
812
  name: "kit_install_preview",
795
813
  title: "Preview Kit Install",
796
- description: "The kit's install form plus this account's current ability to satisfy it — call this BEFORE kit_install and gather every answer it demands. Creates nothing. Requires the installKits scope (403 names it). Returns: requiredInputs (EVERY key is mandatory at install — collect a value for each from the human, keys are exact), memorySetup (questions whose answers become the worker's first memory; only required:true entries are mandatory), modelType, decisionSetup, decisionNarration (a 'decision' kit runs a routing table instead of an instruction, on no model you pick: decisionNarration is that table as sentences — brief the human from it; decisionSetup are its install questions, answered by key in kit_install's decisionAnswers — a required one with no default is mandatory, except an appPick, answerable later with instruction_set; the worker's table acts from its first run), categorySlots (pick ONE member per slot via categoryChoices; each member carries connection — prefer a connected one — and connectionProvider, which when set means also pass categoryChoices[].resourceId picked from operatorResources, ideally one with hasActiveConnection and a matching provider), apps + appsNeedingConnection (the connection state the new worker would START with; installing anyway is allowed — the worker starts blocked and a human finishes at connectAppsUrl), operator (which operator the install targets), limits (currentWorkers/maxWorkers — at the cap the install returns 402), kitPageUrl (the human install page). Preview is advisory: the install response's readiness block is the verdict. For the kit's full permissions manifest and instruction use kit_get on the public Directory server.",
814
+ description: "The kit's install form plus this account's current ability to satisfy it — call this BEFORE kit_install and gather every answer it demands. Creates nothing. Requires the installKits scope (403 names it). Returns: requiredInputs (EVERY key is mandatory at install — collect a value for each from the human, keys are exact), memorySetup (questions whose answers become the worker's first memory; only required:true entries are mandatory), modelType, decisionSetup, decisionNarration (a 'decision' kit runs a routing table instead of an instruction, on no model you pick: decisionNarration is that table as sentences — brief the human from it; decisionSetup are its install questions, answered by key in kit_install's decisionAnswers — a required one with no default is mandatory, except an appPick, answerable later with instruction_set; the worker's table acts from its first run), categorySlots (pick ONE member per slot via categoryChoices; each member carries connection — prefer a connected one — and connectionProvider, which when set means also pass categoryChoices[].resourceId picked from operatorResources, ideally one with hasActiveConnection and a matching provider), apps + appsNeedingConnection (the connection state the new worker would START with; installing anyway is allowed — the worker starts blocked and a human finishes at connectAppsUrl), githubAccounts (the operator's connected GitHub accounts; each id is a connectionId for kit_install's githubSelection), operator (which operator the install targets), limits (currentWorkers/maxWorkers — at the cap the install returns 402), kitPageUrl (the human install page). Preview is advisory: the install response's readiness block is the verdict. For the kit's full permissions manifest and instruction use kit_get on the public Directory server.",
797
815
  auth: "manager",
798
816
  method: "get",
799
817
  schema: {
@@ -818,6 +836,7 @@ const kitInstall = {
818
836
  operatorId: z.string().uuid().optional().describe("Operator (workspace) to install into. Omit to use the account's default operator."),
819
837
  title: z.string().max(100).optional().describe("Name for the new worker (≤100 chars). Omit to use the kit's name."),
820
838
  avatar: z.string().max(40).optional().describe("Avatar slug for the new worker. Omit for the default."),
839
+ githubSelection: GITHUB_SELECTION.optional().describe("GitHub accounts to grant the new worker. connectionId is a githubAccounts[].id from kit_install_preview. repositoryMode 'all' covers every repository granted to that account, including ones granted later; 'selected' takes 1-500 repositoryIds. An empty accounts list leaves GitHub setup for later. Omit to grant the operator's only connected account with all repositories; several connected accounts are never selected implicitly."),
821
840
  categoryChoices: z.array(z.object({
822
841
  categoryCode: z.string().describe("The slot's categoryCode from the preview."),
823
842
  memberCode: z.string().describe("The chosen member's code (e.g. 'gmail')."),
@@ -840,6 +859,7 @@ const kitInstall = {
840
859
  operatorId: params.operatorId,
841
860
  title: params.title,
842
861
  avatar: params.avatar,
862
+ githubSelection: params.githubSelection,
843
863
  categoryChoices: params.categoryChoices,
844
864
  inputs: params.inputs,
845
865
  memoryAnswers: params.memoryAnswers,
@@ -1375,7 +1395,7 @@ const deleteKit = {
1375
1395
  const APPS_API = "/api/manage/apps";
1376
1396
  const MODEL_KEYS_API = "/api/manage/model-keys";
1377
1397
  const OPERATOR_ID_HINT = "The operator (workspace) to act for, as a GUID from apps_list → operators[]. Omit for the account's default operator — the one installs and clones land on. Account-level providers ignore it.";
1378
- const PROVIDER_HINT = "A recipe's provider code from apps_list → apps[].connect[].provider: telegram, discord, slack, twilio, sendgrid, resend, tavily, brave, exa, brightData, firecrawl, granola, krisp, gong, zendesk, shopify, hubspot, notion, linear, monday, jira, asana, confluence, or mcp:<slug> for an MCP app (a platform one, or one of your own from mcp_servers_list — published or not). Case-insensitive.";
1398
+ const PROVIDER_HINT = "A recipe's provider code from apps_list → apps[].connect[].provider: telegram, discord, slack, twilio, sendgrid, resend, tavily, brave, exa, brightData, firecrawl, nimble, granola, krisp, gong, zendesk, shopify, hubspot, notion, linear, monday, jira, asana, confluence, or mcp:<slug> for an MCP app (a platform one, or one of your own from mcp_servers_list — published or not). Case-insensitive.";
1379
1399
  const listApps = {
1380
1400
  name: "apps_list",
1381
1401
  title: "List Connected Apps",