@zackbart/connecta 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +83 -7
  3. package/SECURITY.md +10 -6
  4. package/dist/activity.d.ts +8 -0
  5. package/dist/activity.d.ts.map +1 -1
  6. package/dist/activity.js +1 -0
  7. package/dist/activity.js.map +1 -1
  8. package/dist/auth/bearer.d.ts +10 -3
  9. package/dist/auth/bearer.d.ts.map +1 -1
  10. package/dist/auth/bearer.js +21 -0
  11. package/dist/auth/bearer.js.map +1 -1
  12. package/dist/auth/clerk.d.ts +26 -1
  13. package/dist/auth/clerk.d.ts.map +1 -1
  14. package/dist/auth/clerk.js +161 -4
  15. package/dist/auth/clerk.js.map +1 -1
  16. package/dist/connectors/api.d.ts +13 -0
  17. package/dist/connectors/api.d.ts.map +1 -1
  18. package/dist/connectors/api.js +2 -0
  19. package/dist/connectors/api.js.map +1 -1
  20. package/dist/connectors/remote-mcp.d.ts +13 -0
  21. package/dist/connectors/remote-mcp.d.ts.map +1 -1
  22. package/dist/connectors/remote-mcp.js +10 -0
  23. package/dist/connectors/remote-mcp.js.map +1 -1
  24. package/dist/credential-health.d.ts +212 -0
  25. package/dist/credential-health.d.ts.map +1 -0
  26. package/dist/credential-health.js +535 -0
  27. package/dist/credential-health.js.map +1 -0
  28. package/dist/execute.d.ts +4 -4
  29. package/dist/execute.d.ts.map +1 -1
  30. package/dist/execute.js +16 -4
  31. package/dist/execute.js.map +1 -1
  32. package/dist/index.d.ts +77 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +112 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/meta-tools.d.ts +76 -7
  37. package/dist/meta-tools.d.ts.map +1 -1
  38. package/dist/meta-tools.js +328 -98
  39. package/dist/meta-tools.js.map +1 -1
  40. package/dist/registry.d.ts +245 -2
  41. package/dist/registry.d.ts.map +1 -1
  42. package/dist/registry.js +377 -27
  43. package/dist/registry.js.map +1 -1
  44. package/dist/server.d.ts +7 -1
  45. package/dist/server.d.ts.map +1 -1
  46. package/dist/server.js +342 -27
  47. package/dist/server.js.map +1 -1
  48. package/dist/skills.d.ts +53 -2
  49. package/dist/skills.d.ts.map +1 -1
  50. package/dist/skills.js +162 -2
  51. package/dist/skills.js.map +1 -1
  52. package/dist/timeout.d.ts +16 -0
  53. package/dist/timeout.d.ts.map +1 -0
  54. package/dist/timeout.js +38 -0
  55. package/dist/timeout.js.map +1 -0
  56. package/dist/toolkits.d.ts +138 -0
  57. package/dist/toolkits.d.ts.map +1 -0
  58. package/dist/toolkits.js +319 -0
  59. package/dist/toolkits.js.map +1 -0
  60. package/dist/types.d.ts +90 -1
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/ui.d.ts +63 -0
  63. package/dist/ui.d.ts.map +1 -1
  64. package/dist/ui.js +176 -11
  65. package/dist/ui.js.map +1 -1
  66. package/dist/version.d.ts +1 -1
  67. package/dist/version.js +1 -1
  68. package/package.json +5 -2
  69. package/src/activity.ts +9 -0
  70. package/src/auth/bearer.ts +35 -1
  71. package/src/auth/clerk.ts +202 -5
  72. package/src/connectors/api.ts +15 -0
  73. package/src/connectors/remote-mcp.ts +24 -0
  74. package/src/credential-health.ts +736 -0
  75. package/src/execute.ts +32 -8
  76. package/src/index.ts +226 -2
  77. package/src/meta-tools.ts +397 -119
  78. package/src/registry.ts +540 -29
  79. package/src/server.ts +431 -25
  80. package/src/skills.ts +185 -2
  81. package/src/timeout.ts +49 -0
  82. package/src/toolkits.ts +450 -0
  83. package/src/types.ts +96 -2
  84. package/src/ui.ts +190 -11
  85. package/src/version.ts +1 -1
package/dist/skills.d.ts CHANGED
@@ -1,8 +1,59 @@
1
+ import type { Connector } from "./types.js";
1
2
  export declare const CONNECTA_INSTRUCTIONS = "Connecta exposes many integrations behind meta-tools. When an address is unknown, start with search_tools and includeSchemas=\"compact\"; use describe_tools only when that schema is insufficient. Use call_tool for one explicitly read-only call, batch_call for 2\u201310 independent explicitly read-only calls, and execute_code (when available) only for dependent read-only steps, loops, joins, or reducing large results. Unannotated, write-capable, and destructive tools must use call_destructive_tool individually. Use authorize_connector only after auth_required and get_result only for truncated results. For the detailed workflow, call skills({ name: \"usage\" }) once per task.";
2
- export declare const USAGE_SKILL = "# Connecta usage\n\n## Choose the smallest execution tool\n\n- Unknown address: `search_tools({ query, includeSchemas: \"compact\" })`.\n- Schema still unclear: `describe_tools({ addresses: [...] })`.\n- One explicitly read-only call: `call_tool`.\n- Two to ten independent explicitly read-only calls: `batch_call`.\n- Dependent read-only calls, loops, joins, branching, or large-result reduction: `execute_code` when available.\n- Any unannotated, write-capable, or destructive call: `call_destructive_tool`, individually and only after reviewing its schema and consequences.\n- Truncated result: retry with `fields` when possible; otherwise page it with `get_result`.\n- `auth_required`: use `authorize_connector`, have the operator complete consent, then confirm with `list_connectors`.\n\nUse `list_connectors({ probe: false })` for a fast inventory. Use `probe: true` only when diagnosing live health or authorization.\n\n## Code mode\n\nUse code mode when a later call depends on an earlier result, when joining across connectors, or when filtering or aggregating data in the sandbox will substantially shrink the response. Use `Promise.all` or `connecta.batch` for independent calls inside one execution.\n\nDo not use code mode for one straightforward call, for independent calls already handled by `batch_call`, or for any tool not explicitly annotated `readOnlyHint: true`. Code mode has a bounded host-call budget and per-call deadline. Return only the reduced value the agent needs; do not return a large upstream payload unchanged.\n\n## Examples\n\nThese addresses are illustrative; always use the exact address returned by `search_tools`.\n\nSingle call:\n```json\n{ \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" }, \"resultMode\": \"value\" }\n```\n\nIndependent calls:\n```json\n{ \"calls\": [\n { \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" } },\n { \"address\": \"billing.list_invoices\", \"args\": { \"status\": \"open\" } }\n] }\n```\n\nDependent code with reduction:\n```js\nasync () => {\n const accounts = await crm.search_accounts({ query: \"renewal\" });\n const details = await Promise.all(\n accounts.results.slice(0, 5).map((account) =>\n crm.get_account({ id: account.id })\n )\n );\n return details.map(({ id, name, status }) => ({ id, name, status }));\n}\n```\n";
3
+ export declare const USAGE_SKILL = "# Connecta usage\n\n## Choose the smallest execution tool\n\n- Unknown address: `search_tools({ query, includeSchemas: \"compact\" })`.\n- Schema still unclear: `describe_tools({ addresses: [...] })`.\n- One explicitly read-only call: `call_tool`.\n- Two to ten independent explicitly read-only calls: `batch_call`.\n- Dependent read-only calls, loops, joins, branching, or large-result reduction: `execute_code` when available.\n- Any unannotated, write-capable, or destructive call: `call_destructive_tool`, individually and only after reviewing its schema and consequences.\n- Truncated result: retry with `fields` when possible; otherwise page it with `get_result`.\n- `auth_required`: use `authorize_connector`, have the operator complete consent, then confirm with `list_connectors`.\n\nUse `list_connectors({ probe: false })` for a fast inventory. Use `probe: true` only when diagnosing live health or authorization. The fast inventory already reports a connector whose stored credential failed a proactive check as `auth_required` (with `credentialCheck` and the URL to open), so trust it and authorize up front rather than probing to confirm.\n\n## Code mode\n\nUse code mode when a later call depends on an earlier result, when joining across connectors, or when filtering or aggregating data in the sandbox will substantially shrink the response. Use `Promise.all` or `connecta.batch` for independent calls inside one execution.\n\nDo not use code mode for one straightforward call, for independent calls already handled by `batch_call`, or for any tool not explicitly annotated `readOnlyHint: true`. Code mode has a bounded host-call budget and per-call deadline. Return only the reduced value the agent needs; do not return a large upstream payload unchanged.\n\n## Examples\n\nThese addresses are illustrative; always use the exact address returned by `search_tools`.\n\nSingle call:\n```json\n{ \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" }, \"resultMode\": \"value\" }\n```\n\nIndependent calls:\n```json\n{ \"calls\": [\n { \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" } },\n { \"address\": \"billing.list_invoices\", \"args\": { \"status\": \"open\" } }\n] }\n```\n\nDependent code with reduction:\n```js\nasync () => {\n const accounts = await crm.search_accounts({ query: \"renewal\" });\n const details = await Promise.all(\n accounts.results.slice(0, 5).map((account) =>\n crm.get_account({ id: account.id })\n )\n );\n return details.map(({ id, name, status }) => ({ id, name, status }));\n}\n```\n";
4
+ /**
5
+ * Appended to USAGE_SKILL only when the deployment actually has at least one
6
+ * connector guide. A deployment with none — every deployment that has not
7
+ * adopted the feature — keeps the base guide byte-for-byte, rather than paying
8
+ * context for an instruction to fetch guides that do not exist.
9
+ */
10
+ export declare const CONNECTOR_GUIDES_SECTION = "\n## Per-connector guides\n\nSome connectors here ship their own usage guide \u2014 preferred tools, address quirks, pagination conventions, rate-limit etiquette, query patterns. `skills({})` lists each one as `connector:<connectorId>`; fetch it with `skills({ name: \"connector:<connectorId>\" })`. `search_tools` and `describe_tools` set `guide` on matches whose connector has one. Read a connector's guide before working with it for the first time in a task.\n";
11
+ /** True when at least one of `connectors` carries a usage guide. */
12
+ export declare function hasConnectorGuides(connectors: readonly Connector[]): boolean;
13
+ /** The built-in usage guide, plus the guides section when there is one to point at. */
14
+ export declare function usageSkill(connectors: readonly Connector[]): string;
3
15
  export declare const AVAILABLE_SKILLS: readonly [{
4
16
  readonly name: "usage";
5
17
  readonly description: "How to choose among Connecta discovery, direct, batch, destructive, and code-mode tools.";
6
- readonly content: "# Connecta usage\n\n## Choose the smallest execution tool\n\n- Unknown address: `search_tools({ query, includeSchemas: \"compact\" })`.\n- Schema still unclear: `describe_tools({ addresses: [...] })`.\n- One explicitly read-only call: `call_tool`.\n- Two to ten independent explicitly read-only calls: `batch_call`.\n- Dependent read-only calls, loops, joins, branching, or large-result reduction: `execute_code` when available.\n- Any unannotated, write-capable, or destructive call: `call_destructive_tool`, individually and only after reviewing its schema and consequences.\n- Truncated result: retry with `fields` when possible; otherwise page it with `get_result`.\n- `auth_required`: use `authorize_connector`, have the operator complete consent, then confirm with `list_connectors`.\n\nUse `list_connectors({ probe: false })` for a fast inventory. Use `probe: true` only when diagnosing live health or authorization.\n\n## Code mode\n\nUse code mode when a later call depends on an earlier result, when joining across connectors, or when filtering or aggregating data in the sandbox will substantially shrink the response. Use `Promise.all` or `connecta.batch` for independent calls inside one execution.\n\nDo not use code mode for one straightforward call, for independent calls already handled by `batch_call`, or for any tool not explicitly annotated `readOnlyHint: true`. Code mode has a bounded host-call budget and per-call deadline. Return only the reduced value the agent needs; do not return a large upstream payload unchanged.\n\n## Examples\n\nThese addresses are illustrative; always use the exact address returned by `search_tools`.\n\nSingle call:\n```json\n{ \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" }, \"resultMode\": \"value\" }\n```\n\nIndependent calls:\n```json\n{ \"calls\": [\n { \"address\": \"crm.get_account\", \"args\": { \"id\": \"acct_123\" } },\n { \"address\": \"billing.list_invoices\", \"args\": { \"status\": \"open\" } }\n] }\n```\n\nDependent code with reduction:\n```js\nasync () => {\n const accounts = await crm.search_accounts({ query: \"renewal\" });\n const details = await Promise.all(\n accounts.results.slice(0, 5).map((account) =>\n crm.get_account({ id: account.id })\n )\n );\n return details.map(({ id, name, status }) => ({ id, name, status }));\n}\n```\n";
18
+ readonly content: typeof usageSkill;
7
19
  }];
20
+ /**
21
+ * Namespace for operator-authored per-connector guides. Built-in skill names
22
+ * are bare identifiers and never contain ":", so `connector:<id>` cannot
23
+ * collide with one — not even when a connector's id is literally "usage".
24
+ * The prefixed form is the ONLY way to reach a connector guide: a bare
25
+ * connector id is never resolved, so nothing shadows anything silently.
26
+ */
27
+ export declare const CONNECTOR_SKILL_PREFIX = "connector:";
28
+ /** The skill name that fetches `connector`'s guide. */
29
+ export declare function connectorSkillName(connectorId: string): string;
30
+ /** The connector's guide, or undefined when it declares none (or a blank one). */
31
+ export declare function connectorGuide(connector: Connector): string | undefined;
32
+ export interface SkillListing {
33
+ name: string;
34
+ description: string;
35
+ }
36
+ /**
37
+ * Every fetchable skill: the built-in guides plus one entry per connector that
38
+ * carries a usage guide. Derived from the connector list passed in — the single
39
+ * place guide visibility is decided. The `skills` meta-tool passes its
40
+ * connection's `registry.listConnectors()`, so a toolkit-scoped session lists
41
+ * only in-scope guides, and `resolveSkill` below reports an out-of-scope
42
+ * `connector:<id>` exactly as it reports an unknown connector.
43
+ */
44
+ export declare function listSkills(connectors: readonly Connector[]): SkillListing[];
45
+ export type SkillLookup = {
46
+ found: true;
47
+ content: string;
48
+ } | {
49
+ found: false;
50
+ message: string;
51
+ };
52
+ /**
53
+ * Resolve one skill name. Built-in names match exactly; connector guides are
54
+ * reachable only through the `connector:` prefix. Every miss — unknown name,
55
+ * unknown connector, connector without a guide — is an explicit error, never a
56
+ * silent fallback to the generic guide.
57
+ */
58
+ export declare function resolveSkill(name: string, connectors: readonly Connector[]): SkillLookup;
8
59
  //# sourceMappingURL=skills.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,+qBACmoB,CAAC;AAEtqB,eAAO,MAAM,WAAW,wzEAkDvB,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;;EAOnB,CAAC"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,eAAO,MAAM,qBAAqB,+qBACmoB,CAAC;AAEtqB,eAAO,MAAM,WAAW,4hFAkDvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,odAIpC,CAAC;AAEF,oEAAoE;AACpE,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAI5E;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CAInE;AAED,eAAO,MAAM,gBAAgB;;;;EAOnB,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAGvE;AAwDD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,YAAY,EAAE,CAc3E;AAED,MAAM,MAAM,WAAW,GACrB;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,SAAS,SAAS,EAAE,GAC/B,WAAW,CAsCb"}
package/dist/skills.js CHANGED
@@ -12,7 +12,7 @@ export const USAGE_SKILL = `# Connecta usage
12
12
  - Truncated result: retry with \`fields\` when possible; otherwise page it with \`get_result\`.
13
13
  - \`auth_required\`: use \`authorize_connector\`, have the operator complete consent, then confirm with \`list_connectors\`.
14
14
 
15
- Use \`list_connectors({ probe: false })\` for a fast inventory. Use \`probe: true\` only when diagnosing live health or authorization.
15
+ Use \`list_connectors({ probe: false })\` for a fast inventory. Use \`probe: true\` only when diagnosing live health or authorization. The fast inventory already reports a connector whose stored credential failed a proactive check as \`auth_required\` (with \`credentialCheck\` and the URL to open), so trust it and authorize up front rather than probing to confirm.
16
16
 
17
17
  ## Code mode
18
18
 
@@ -50,11 +50,171 @@ async () => {
50
50
  }
51
51
  \`\`\`
52
52
  `;
53
+ /**
54
+ * Appended to USAGE_SKILL only when the deployment actually has at least one
55
+ * connector guide. A deployment with none — every deployment that has not
56
+ * adopted the feature — keeps the base guide byte-for-byte, rather than paying
57
+ * context for an instruction to fetch guides that do not exist.
58
+ */
59
+ export const CONNECTOR_GUIDES_SECTION = `
60
+ ## Per-connector guides
61
+
62
+ Some connectors here ship their own usage guide — preferred tools, address quirks, pagination conventions, rate-limit etiquette, query patterns. \`skills({})\` lists each one as \`connector:<connectorId>\`; fetch it with \`skills({ name: "connector:<connectorId>" })\`. \`search_tools\` and \`describe_tools\` set \`guide\` on matches whose connector has one. Read a connector's guide before working with it for the first time in a task.
63
+ `;
64
+ /** True when at least one of `connectors` carries a usage guide. */
65
+ export function hasConnectorGuides(connectors) {
66
+ return connectors.some((connector) => connectorGuide(connector) !== undefined);
67
+ }
68
+ /** The built-in usage guide, plus the guides section when there is one to point at. */
69
+ export function usageSkill(connectors) {
70
+ return hasConnectorGuides(connectors)
71
+ ? USAGE_SKILL + CONNECTOR_GUIDES_SECTION
72
+ : USAGE_SKILL;
73
+ }
53
74
  export const AVAILABLE_SKILLS = [
54
75
  {
55
76
  name: "usage",
56
77
  description: "How to choose among Connecta discovery, direct, batch, destructive, and code-mode tools.",
57
- content: USAGE_SKILL,
78
+ content: usageSkill,
58
79
  },
59
80
  ];
81
+ /**
82
+ * Namespace for operator-authored per-connector guides. Built-in skill names
83
+ * are bare identifiers and never contain ":", so `connector:<id>` cannot
84
+ * collide with one — not even when a connector's id is literally "usage".
85
+ * The prefixed form is the ONLY way to reach a connector guide: a bare
86
+ * connector id is never resolved, so nothing shadows anything silently.
87
+ */
88
+ export const CONNECTOR_SKILL_PREFIX = "connector:";
89
+ /** The skill name that fetches `connector`'s guide. */
90
+ export function connectorSkillName(connectorId) {
91
+ return `${CONNECTOR_SKILL_PREFIX}${connectorId}`;
92
+ }
93
+ /** The connector's guide, or undefined when it declares none (or a blank one). */
94
+ export function connectorGuide(connector) {
95
+ const guide = connector.usageGuide;
96
+ return guide && guide.trim() !== "" ? guide : undefined;
97
+ }
98
+ const SUMMARY_LENGTH = 120;
99
+ /** A `---`/`***`/`___` rule, which also opens and closes YAML frontmatter. */
100
+ const RULE_RE = /^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/;
101
+ /** A fenced code block's delimiter. */
102
+ const FENCE_RE = /^\s*(?:```|~~~)/;
103
+ /**
104
+ * Markup that carries no summary text of its own: horizontal rules, HTML
105
+ * comments, and table rows. Skipped so a guide that opens with one is
106
+ * summarized by its first real line instead of by punctuation.
107
+ */
108
+ const NOT_SUMMARY_RE = /^\s*(?:<!--|\|)|^\s*(?:-{3,}|\*{3,}|_{3,})\s*$/;
109
+ /** Drop a leading YAML frontmatter block — metadata, not summary text. */
110
+ function withoutFrontmatter(lines) {
111
+ let start = 0;
112
+ while (start < lines.length && lines[start].trim() === "")
113
+ start++;
114
+ if (start >= lines.length || !RULE_RE.test(lines[start]))
115
+ return lines;
116
+ const close = lines.findIndex((line, i) => i > start && RULE_RE.test(line));
117
+ return close === -1 ? lines : lines.slice(close + 1);
118
+ }
119
+ /**
120
+ * One line describing a guide, for the cheap list view: the guide's first
121
+ * meaningful line (heading marks and list bullets stripped), falling back to
122
+ * the connector's own description when the guide opens with nothing but
123
+ * markup.
124
+ */
125
+ function summarizeGuide(connector, guide) {
126
+ let inFence = false;
127
+ for (const raw of withoutFrontmatter(guide.split("\n"))) {
128
+ if (FENCE_RE.test(raw)) {
129
+ inFence = !inFence;
130
+ continue;
131
+ }
132
+ if (inFence)
133
+ continue;
134
+ if (raw.trim() === "" || NOT_SUMMARY_RE.test(raw))
135
+ continue;
136
+ const line = raw
137
+ // `\s*` (not `\s+`) so a bare `#` strips to nothing and is skipped, and
138
+ // an unspaced `#Heading` is still read as a heading.
139
+ .replace(/^\s*#{1,6}\s*/, "")
140
+ .replace(/^\s*[-*+]\s+/, "")
141
+ .replace(/\s+/g, " ")
142
+ .trim();
143
+ if (line === "")
144
+ continue;
145
+ return line.length <= SUMMARY_LENGTH
146
+ ? line
147
+ : `${line.slice(0, SUMMARY_LENGTH - 1).trimEnd()}…`;
148
+ }
149
+ return connector.description ?? `Usage guide for "${connector.id}".`;
150
+ }
151
+ /**
152
+ * Every fetchable skill: the built-in guides plus one entry per connector that
153
+ * carries a usage guide. Derived from the connector list passed in — the single
154
+ * place guide visibility is decided. The `skills` meta-tool passes its
155
+ * connection's `registry.listConnectors()`, so a toolkit-scoped session lists
156
+ * only in-scope guides, and `resolveSkill` below reports an out-of-scope
157
+ * `connector:<id>` exactly as it reports an unknown connector.
158
+ */
159
+ export function listSkills(connectors) {
160
+ const listing = AVAILABLE_SKILLS.map((skill) => ({
161
+ name: skill.name,
162
+ description: skill.description,
163
+ }));
164
+ for (const connector of connectors) {
165
+ const guide = connectorGuide(connector);
166
+ if (!guide)
167
+ continue;
168
+ listing.push({
169
+ name: connectorSkillName(connector.id),
170
+ description: summarizeGuide(connector, guide),
171
+ });
172
+ }
173
+ return listing;
174
+ }
175
+ /**
176
+ * Resolve one skill name. Built-in names match exactly; connector guides are
177
+ * reachable only through the `connector:` prefix. Every miss — unknown name,
178
+ * unknown connector, connector without a guide — is an explicit error, never a
179
+ * silent fallback to the generic guide.
180
+ */
181
+ export function resolveSkill(name, connectors) {
182
+ const builtIn = AVAILABLE_SKILLS.find((skill) => skill.name === name);
183
+ if (builtIn)
184
+ return { found: true, content: builtIn.content(connectors) };
185
+ const available = () => listSkills(connectors)
186
+ .map((skill) => skill.name)
187
+ .join(", ");
188
+ if (name.startsWith(CONNECTOR_SKILL_PREFIX)) {
189
+ const id = name.slice(CONNECTOR_SKILL_PREFIX.length);
190
+ const connector = connectors.find((c) => c.id === id);
191
+ if (!connector) {
192
+ return {
193
+ found: false,
194
+ message: `Unknown connector "${id}". Available skills: ${available()}.`,
195
+ };
196
+ }
197
+ const guide = connectorGuide(connector);
198
+ if (!guide) {
199
+ return {
200
+ found: false,
201
+ message: `Connector "${id}" has no usage guide. Available skills: ${available()}.`,
202
+ };
203
+ }
204
+ return { found: true, content: guide };
205
+ }
206
+ const bare = connectors.find((c) => c.id === name);
207
+ if (bare) {
208
+ return {
209
+ found: false,
210
+ message: connectorGuide(bare)
211
+ ? `Unknown skill "${name}". Connector guides are fetched as "${connectorSkillName(name)}". Available: ${available()}.`
212
+ : `Connector "${name}" has no usage guide. Available skills: ${available()}.`,
213
+ };
214
+ }
215
+ return {
216
+ found: false,
217
+ message: `Unknown skill "${name}". Available: ${available()}.`,
218
+ };
219
+ }
60
220
  //# sourceMappingURL=skills.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,qBAAqB,GAChC,mqBAAmqB,CAAC;AAEtqB,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkD1B,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;QACE,IAAI,EAAE,OAAO;QACb,WAAW,EACT,0FAA0F;QAC5F,OAAO,EAAE,WAAW;KACrB;CACO,CAAC"}
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Generous default bound for a single downstream probe/catalog call. High enough
3
+ * to trip only on a pathological hang, not a realistically slow probe.
4
+ */
5
+ export declare const DEFAULT_PROBE_TIMEOUT_MS = 30000;
6
+ /** A finite, positive integer number of milliseconds, or undefined. */
7
+ export declare function normalizeTimeoutMs(value: number | undefined): number | undefined;
8
+ /**
9
+ * Reject `promise` after `ms` if it has not settled, so one hung downstream
10
+ * cannot stall a whole fan-out. NOTE: this bounds only the caller-facing wait —
11
+ * the registry probe methods take no AbortSignal, so the underlying fetch is
12
+ * NOT cancelled and keeps running in the background. Real cancellation
13
+ * (AbortSignal plumbed through the registry) is a deferred follow-up.
14
+ */
15
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T>;
16
+ //# sourceMappingURL=timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C,uEAAuE;AACvE,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,GAAG,SAAS,CAKpB;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,CAAC,CAAC,CAgBZ"}
@@ -0,0 +1,38 @@
1
+ // The deadline vocabulary shared by every non-call downstream probe: the
2
+ // discovery meta-tools' catalog fan-out (src/meta-tools.ts) and the credential
3
+ // liveness checks (src/credential-health.ts). One definition so a "probe" means
4
+ // the same thing, and is bounded the same way, wherever one is issued.
5
+ /**
6
+ * Generous default bound for a single downstream probe/catalog call. High enough
7
+ * to trip only on a pathological hang, not a realistically slow probe.
8
+ */
9
+ export const DEFAULT_PROBE_TIMEOUT_MS = 30_000;
10
+ /** A finite, positive integer number of milliseconds, or undefined. */
11
+ export function normalizeTimeoutMs(value) {
12
+ if (value === undefined || !Number.isFinite(value) || !(value > 0)) {
13
+ return undefined;
14
+ }
15
+ return Math.max(1, Math.trunc(value));
16
+ }
17
+ /**
18
+ * Reject `promise` after `ms` if it has not settled, so one hung downstream
19
+ * cannot stall a whole fan-out. NOTE: this bounds only the caller-facing wait —
20
+ * the registry probe methods take no AbortSignal, so the underlying fetch is
21
+ * NOT cancelled and keeps running in the background. Real cancellation
22
+ * (AbortSignal plumbed through the registry) is a deferred follow-up.
23
+ */
24
+ export function withTimeout(promise, ms, label) {
25
+ return new Promise((resolve, reject) => {
26
+ const timer = setTimeout(() => {
27
+ reject(new Error(`${label} timed out after ${ms}ms`));
28
+ }, ms);
29
+ promise.then((value) => {
30
+ clearTimeout(timer);
31
+ resolve(value);
32
+ }, (err) => {
33
+ clearTimeout(timer);
34
+ reject(err);
35
+ });
36
+ });
37
+ }
38
+ //# sourceMappingURL=timeout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.js","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,+EAA+E;AAC/E,gFAAgF;AAChF,uEAAuE;AAEvE;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAE/C,uEAAuE;AACvE,MAAM,UAAU,kBAAkB,CAChC,KAAyB;IAEzB,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;QACnE,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,OAAmB,EACnB,EAAU,EACV,KAAa;IAEb,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,KAAK,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC;QACxD,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;YACR,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,CAAC,GAAG,EAAE,EAAE;YACN,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,138 @@
1
+ import type { Connector, InboundAuth, ToolkitBinding } from "./types.js";
2
+ /** Toolkit names share the connector-id grammar: URL-safe, no separators. */
3
+ export declare const TOOLKIT_NAME_RE: RegExp;
4
+ /** One named scope, declared in `ConnectaConfig.toolkits` (config as code). */
5
+ export interface ToolkitDefinition {
6
+ /** Connector ids this toolkit may see. Required, and at least one. */
7
+ connectors: string[];
8
+ /**
9
+ * Optional finer grain: full tool addresses (`"<connectorId>.<toolName>"`).
10
+ * Naming ANY address of a connector narrows that connector to exactly the
11
+ * addresses named; connectors with no entry here keep their whole tool list.
12
+ */
13
+ includeTools?: string[];
14
+ /** Optional tool addresses to hide, applied after `includeTools`. */
15
+ excludeTools?: string[];
16
+ /** Operator note. Never sent to clients — this is documentation for config. */
17
+ description?: string;
18
+ }
19
+ /** `ConnectaConfig.toolkits` — toolkit name → definition. */
20
+ export type ToolkitConfig = Record<string, ToolkitDefinition>;
21
+ /** A validated toolkit: the visibility predicate the scoped registry consults. */
22
+ export interface Toolkit {
23
+ readonly name: string;
24
+ readonly description?: string;
25
+ /** True when `connectorId` is inside this toolkit's scope. */
26
+ hasConnector(connectorId: string): boolean;
27
+ /** True when `<connectorId>.<toolName>` is inside this toolkit's scope. */
28
+ hasTool(connectorId: string, toolName: string): boolean;
29
+ }
30
+ /**
31
+ * Split `"<connectorId>.<toolName>"` on the FIRST dot — connector ids contain
32
+ * no dots, so a downstream tool name may. Returns null for a malformed address.
33
+ */
34
+ export declare function splitAddress(address: string): {
35
+ connectorId: string;
36
+ toolName: string;
37
+ } | null;
38
+ /**
39
+ * Validate every declared toolkit against the connector set. Returns undefined
40
+ * when no toolkits are configured, so an existing deployment keeps exactly its
41
+ * current (unscoped) behavior.
42
+ */
43
+ export declare function resolveToolkits(toolkits: ToolkitConfig | undefined, connectors: readonly Connector[]): ReadonlyMap<string, Toolkit> | undefined;
44
+ /**
45
+ * The binding half of an inbound-auth adapter's options — the shape every
46
+ * shipped adapter (`bearerToken`, `clerkAuth`) mixes into its own options so an
47
+ * operator writes one thing in one style, next to the credential it binds.
48
+ */
49
+ export interface ToolkitBindingOptions {
50
+ /**
51
+ * Toolkit names this credential may select with `?toolkit=<name>`. Present ⇒
52
+ * the identity is BOUND: any other toolkit, and (unless `unscoped`) a
53
+ * connection with no `?toolkit=`, is refused at connect time. Absent ⇒
54
+ * unbound, exactly as before bindings existed.
55
+ */
56
+ toolkits?: readonly string[];
57
+ /**
58
+ * Also allow a connection with no `?toolkit=` (the full registry, and the
59
+ * deployment-wide operator surfaces). Only meaningful beside `toolkits`.
60
+ */
61
+ unscoped?: boolean;
62
+ }
63
+ /**
64
+ * Validate one adapter's binding options into a `ToolkitBinding`, or undefined
65
+ * when the adapter declares none. Structural mistakes THROW where the operator
66
+ * wrote them (adapter construction), for the same reason toolkit definitions do:
67
+ * a binding that does not say what its author meant is worse than none, because
68
+ * it is invisible until the day it denies — or admits — the wrong caller.
69
+ *
70
+ * Names are only checked against the *grammar* here; cross-checking them
71
+ * against the configured toolkits happens in `validateToolkitBindings`, which
72
+ * runs in `createConnecta` where both halves are finally in scope.
73
+ */
74
+ export declare function resolveToolkitBinding(source: string, options: ToolkitBindingOptions): ToolkitBinding | undefined;
75
+ /**
76
+ * Coerce an arbitrary value into a `ToolkitBinding`, or null when it is not one.
77
+ *
78
+ * The shipped adapters build bindings through `resolveToolkitBinding` above, but
79
+ * `InboundAuth` is an open interface and `AuthResult.toolkitBinding` arrives at
80
+ * REQUEST time from code connecta does not own — a custom adapter, or one
81
+ * mapping an IdP claim. Every field is therefore re-checked here rather than
82
+ * trusted from the type, because each way of being wrong fails OPEN if it is
83
+ * merely believed:
84
+ *
85
+ * - `unscoped` is compared to `true` by identity, so a truthy non-boolean (the
86
+ * string `"false"` out of an env var, say) cannot grant the full registry;
87
+ * - `toolkits` must be a real array — a bare string would otherwise reach
88
+ * `String.prototype.includes`, where `?toolkit=sup` would "match" `"support"`
89
+ * by substring;
90
+ * - a missing/!array `toolkits` is not treated as an empty binding, because the
91
+ * caller of a null return refuses the request outright.
92
+ *
93
+ * Returns a frozen, deduplicated copy: nothing downstream can be mutated by the
94
+ * adapter after the check, and every name is known to fit the grammar.
95
+ */
96
+ export declare function normalizeToolkitBinding(value: unknown): ToolkitBinding | null;
97
+ /**
98
+ * Resolve the binding one admitted identity is actually held to, from the
99
+ * provider's static declaration and whatever its `authorize` returned.
100
+ *
101
+ * - Neither ⇒ unbound (undefined), the pre-binding behavior.
102
+ * - Declaration only ⇒ the declaration.
103
+ * - Per-identity only ⇒ that binding, validated. This is the custom-adapter
104
+ * seam: a provider that declares nothing is asserting it resolves membership
105
+ * itself, so there is nothing to check it against.
106
+ * - Both ⇒ the **intersection**. The declaration is a CEILING, not a default: an
107
+ * adapter that maps a user-writable IdP claim to toolkits must not be able to
108
+ * widen the credential's own binding, which would turn "support token" into
109
+ * "any toolkit, plus the full registry" for anyone who can set that claim.
110
+ * Narrowing is fine and useful (per-user subsets of the team's view).
111
+ *
112
+ * A malformed binding on either side is not silently ignored — it returns
113
+ * `{ ok: false }` and the caller refuses the request, because the alternative
114
+ * (dropping it) is the fail-open reading.
115
+ */
116
+ export declare function resolveIdentityBinding(declared: unknown, perIdentity: unknown): {
117
+ ok: true;
118
+ binding?: ToolkitBinding;
119
+ } | {
120
+ ok: false;
121
+ reason: string;
122
+ };
123
+ /**
124
+ * Cross-check every statically declared binding against the deployment's
125
+ * toolkits, in `createConnecta`. A name that no toolkit declares is a typo, and
126
+ * a typo here fails CLOSED — the credential would be refused every connection
127
+ * with a 403 the client reads as a transport failure — so it throws at
128
+ * construction rather than becoming a support ticket. A structurally malformed
129
+ * declaration (only reachable from a hand-written `InboundAuth`, since the
130
+ * shipped adapters validate their own options) throws here too, rather than
131
+ * waiting to refuse every request at runtime.
132
+ *
133
+ * Bindings a provider mints per-identity (`AuthResult.toolkitBinding`) do not
134
+ * exist yet and cannot be checked here; they are validated on arrival and capped
135
+ * by the declaration (`resolveIdentityBinding`).
136
+ */
137
+ export declare function validateToolkitBindings(auth: readonly InboundAuth[], toolkits: ReadonlyMap<string, Toolkit> | undefined): void;
138
+ //# sourceMappingURL=toolkits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolkits.d.ts","sourceRoot":"","sources":["../src/toolkits.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzE,6EAA6E;AAC7E,eAAO,MAAM,eAAe,QAAkB,CAAC;AAE/C,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAE9D,kFAAkF;AAClF,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,8DAA8D;IAC9D,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3C,2EAA2E;IAC3E,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CACzD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,GACd;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAOlD;AAgID;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,UAAU,EAAE,SAAS,SAAS,EAAE,GAC/B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAsB1C;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,qBAAqB,GAC7B,cAAc,GAAG,SAAS,CA2C5B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAmB7E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,OAAO,EACjB,WAAW,EAAE,OAAO,GAElB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,cAAc,CAAA;CAAE,GACtC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAoChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACjD,IAAI,CA2BN"}