@mcoda/codali 0.1.108 → 0.1.110

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 (149) hide show
  1. package/dist/agents/AgentInventory.d.ts +56 -0
  2. package/dist/agents/AgentInventory.d.ts.map +1 -0
  3. package/dist/agents/AgentInventory.js +131 -0
  4. package/dist/agents/RoleResolution.d.ts +49 -0
  5. package/dist/agents/RoleResolution.d.ts.map +1 -0
  6. package/dist/agents/RoleResolution.js +166 -0
  7. package/dist/api/ChatCompletionsAdapter.d.ts +76 -0
  8. package/dist/api/ChatCompletionsAdapter.d.ts.map +1 -0
  9. package/dist/api/ChatCompletionsAdapter.js +54 -0
  10. package/dist/api/CodaliApi.d.ts +78 -0
  11. package/dist/api/CodaliApi.d.ts.map +1 -0
  12. package/dist/api/CodaliApi.js +273 -0
  13. package/dist/api/CodaliServer.d.ts +42 -0
  14. package/dist/api/CodaliServer.d.ts.map +1 -0
  15. package/dist/api/CodaliServer.js +118 -0
  16. package/dist/cli/AskCommand.d.ts +66 -0
  17. package/dist/cli/AskCommand.d.ts.map +1 -0
  18. package/dist/cli/AskCommand.js +536 -0
  19. package/dist/cli/AuthCommand.d.ts +19 -0
  20. package/dist/cli/AuthCommand.d.ts.map +1 -0
  21. package/dist/cli/AuthCommand.js +161 -0
  22. package/dist/cli/ServeCommand.d.ts +5 -0
  23. package/dist/cli/ServeCommand.d.ts.map +1 -0
  24. package/dist/cli/ServeCommand.js +87 -0
  25. package/dist/cli/ToolsCommand.d.ts +22 -0
  26. package/dist/cli/ToolsCommand.d.ts.map +1 -0
  27. package/dist/cli/ToolsCommand.js +208 -0
  28. package/dist/cli.d.ts.map +1 -1
  29. package/dist/cli.js +29 -1
  30. package/dist/connectors/http/HttpToolDefinition.d.ts +74 -0
  31. package/dist/connectors/http/HttpToolDefinition.d.ts.map +1 -0
  32. package/dist/connectors/http/HttpToolDefinition.js +190 -0
  33. package/dist/connectors/http/HttpToolSource.d.ts +18 -0
  34. package/dist/connectors/http/HttpToolSource.d.ts.map +1 -0
  35. package/dist/connectors/http/HttpToolSource.js +29 -0
  36. package/dist/connectors/mcp/McpClient.d.ts +132 -0
  37. package/dist/connectors/mcp/McpClient.d.ts.map +1 -0
  38. package/dist/connectors/mcp/McpClient.js +215 -0
  39. package/dist/connectors/mcp/McpServerRegistry.d.ts +75 -0
  40. package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
  41. package/dist/connectors/mcp/McpServerRegistry.js +180 -0
  42. package/dist/connectors/mcp/McpToolAdapter.d.ts +48 -0
  43. package/dist/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
  44. package/dist/connectors/mcp/McpToolAdapter.js +101 -0
  45. package/dist/connectors/mcp/McpToolSource.d.ts +27 -0
  46. package/dist/connectors/mcp/McpToolSource.d.ts.map +1 -0
  47. package/dist/connectors/mcp/McpToolSource.js +33 -0
  48. package/dist/connectors/media/ImageGenerationTool.d.ts +43 -0
  49. package/dist/connectors/media/ImageGenerationTool.d.ts.map +1 -0
  50. package/dist/connectors/media/ImageGenerationTool.js +122 -0
  51. package/dist/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
  52. package/dist/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
  53. package/dist/connectors/oauth/DeviceCodeAuth.js +153 -0
  54. package/dist/docdex/DocdexClient.d.ts +2 -0
  55. package/dist/docdex/DocdexClient.d.ts.map +1 -1
  56. package/dist/docdex/DocdexClient.js +4 -0
  57. package/dist/gateway/CodaliGateway.d.ts +51 -3
  58. package/dist/gateway/CodaliGateway.d.ts.map +1 -1
  59. package/dist/gateway/CodaliGateway.js +241 -3
  60. package/dist/gateway/CodaliGatewayTypes.d.ts +34 -0
  61. package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -1
  62. package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -1
  63. package/dist/gateway/EvidenceNormalizer.js +98 -1
  64. package/dist/gateway/Finalizer.d.ts +50 -0
  65. package/dist/gateway/Finalizer.d.ts.map +1 -0
  66. package/dist/gateway/Finalizer.js +79 -0
  67. package/dist/gateway/GatewayPlanner.d.ts +13 -0
  68. package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
  69. package/dist/gateway/GatewayPlanner.js +81 -16
  70. package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
  71. package/dist/gateway/GatewayStateMachine.js +6 -0
  72. package/dist/gateway/GatewayTracer.d.ts +93 -0
  73. package/dist/gateway/GatewayTracer.d.ts.map +1 -0
  74. package/dist/gateway/GatewayTracer.js +214 -0
  75. package/dist/gateway/LocalGatewayProvider.d.ts +59 -0
  76. package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
  77. package/dist/gateway/LocalGatewayProvider.js +195 -0
  78. package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
  79. package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
  80. package/dist/gateway/LocalGatewayTaskRunner.js +361 -0
  81. package/dist/gateway/RelevanceJudge.d.ts +25 -0
  82. package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
  83. package/dist/gateway/RelevanceJudge.js +124 -0
  84. package/dist/gateway/ResponseSchema.d.ts +32 -0
  85. package/dist/gateway/ResponseSchema.d.ts.map +1 -0
  86. package/dist/gateway/ResponseSchema.js +120 -0
  87. package/dist/gateway/TemporalContext.d.ts +36 -0
  88. package/dist/gateway/TemporalContext.d.ts.map +1 -0
  89. package/dist/gateway/TemporalContext.js +115 -0
  90. package/dist/gateway/ToolCapabilityCompiler.d.ts +5 -0
  91. package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
  92. package/dist/gateway/ToolCapabilityCompiler.js +27 -2
  93. package/dist/gateway/ToolDescriptorSource.d.ts +6 -0
  94. package/dist/gateway/ToolDescriptorSource.d.ts.map +1 -0
  95. package/dist/gateway/ToolDescriptorSource.js +30 -0
  96. package/dist/gateway/ToolExposure.d.ts +36 -0
  97. package/dist/gateway/ToolExposure.d.ts.map +1 -0
  98. package/dist/gateway/ToolExposure.js +154 -0
  99. package/dist/index.d.ts +57 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +45 -0
  102. package/dist/providers/ClaudeCliProvider.d.ts +2 -0
  103. package/dist/providers/ClaudeCliProvider.d.ts.map +1 -1
  104. package/dist/providers/ClaudeCliProvider.js +2 -0
  105. package/dist/providers/CodexCliProvider.d.ts +2 -0
  106. package/dist/providers/CodexCliProvider.d.ts.map +1 -1
  107. package/dist/providers/CodexCliProvider.js +2 -0
  108. package/dist/providers/MswarmWorkerProvider.d.ts +2 -0
  109. package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
  110. package/dist/providers/MswarmWorkerProvider.js +2 -0
  111. package/dist/providers/OllamaRemoteProvider.d.ts +2 -0
  112. package/dist/providers/OllamaRemoteProvider.d.ts.map +1 -1
  113. package/dist/providers/OllamaRemoteProvider.js +2 -0
  114. package/dist/providers/OpenAiCompatibleProvider.d.ts +2 -0
  115. package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
  116. package/dist/providers/OpenAiCompatibleProvider.js +2 -0
  117. package/dist/providers/ProviderTypes.d.ts +13 -0
  118. package/dist/providers/ProviderTypes.d.ts.map +1 -1
  119. package/dist/providers/ProviderTypes.js +1 -1
  120. package/dist/runcontext/CredentialFile.d.ts +12 -0
  121. package/dist/runcontext/CredentialFile.d.ts.map +1 -0
  122. package/dist/runcontext/CredentialFile.js +81 -0
  123. package/dist/runcontext/RunContextResolver.d.ts +126 -0
  124. package/dist/runcontext/RunContextResolver.d.ts.map +1 -0
  125. package/dist/runcontext/RunContextResolver.js +389 -0
  126. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
  127. package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
  128. package/dist/storage/CodaliDatasetPrivacyEngine.js +12 -0
  129. package/dist/tools/ToolRegistry.d.ts +14 -1
  130. package/dist/tools/ToolRegistry.d.ts.map +1 -1
  131. package/dist/tools/ToolRegistry.js +38 -1
  132. package/dist/tools/ToolTypes.d.ts +35 -0
  133. package/dist/tools/ToolTypes.d.ts.map +1 -1
  134. package/dist/tools/ToolTypes.js +21 -0
  135. package/dist/tools/TruncateResult.d.ts +29 -0
  136. package/dist/tools/TruncateResult.d.ts.map +1 -0
  137. package/dist/tools/TruncateResult.js +91 -0
  138. package/dist/tools/diff/DiffTool.d.ts.map +1 -1
  139. package/dist/tools/diff/DiffTool.js +2 -0
  140. package/dist/tools/docdex/DocdexTools.d.ts +21 -1
  141. package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
  142. package/dist/tools/docdex/DocdexTools.js +151 -17
  143. package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
  144. package/dist/tools/filesystem/FileTools.js +8 -0
  145. package/dist/tools/search/SearchTool.d.ts.map +1 -1
  146. package/dist/tools/search/SearchTool.js +3 -1
  147. package/dist/tools/shell/ShellTool.d.ts.map +1 -1
  148. package/dist/tools/shell/ShellTool.js +2 -0
  149. package/package.json +4 -3
@@ -0,0 +1,389 @@
1
+ import { homedir } from "node:os";
2
+ import path from "node:path";
3
+ import { readFile } from "node:fs/promises";
4
+ import { existsSync } from "node:fs";
5
+ import { resolveCredential } from "./CredentialFile.js";
6
+ /**
7
+ * Keys a repository-level config file is forbidden to set.
8
+ *
9
+ * A checked-out repository is untrusted input. If `.codali/config.toml` could
10
+ * define an MCP server command, a base URL, or a credential reference, then
11
+ * cloning a repository and running `codali ask` inside it would be enough to
12
+ * execute an arbitrary binary or redirect traffic to an attacker's endpoint.
13
+ *
14
+ * The boundary is therefore: user/host config may define what runs and where
15
+ * it connects; repository config may only *narrow* what is already permitted,
16
+ * identify the repository, and set harmless presentation defaults.
17
+ */
18
+ const REPO_FORBIDDEN_KEYS = new Set([
19
+ "command",
20
+ "args",
21
+ "env",
22
+ "url",
23
+ "base_url",
24
+ "baseurl",
25
+ "api_key",
26
+ "apikey",
27
+ "token",
28
+ "secret",
29
+ "credential",
30
+ "credentials",
31
+ "password",
32
+ "headers",
33
+ // Every reader below accepts both snake_case and camelCase, so both spellings
34
+ // must be forbidden. Listing only one is a hole, not a style preference.
35
+ "mcp_servers",
36
+ "mcpservers",
37
+ "api_connectors",
38
+ "apiconnectors",
39
+ "http_connectors",
40
+ "httpconnectors",
41
+ "agents",
42
+ "agent_roles",
43
+ "agentroles",
44
+ "docdex",
45
+ ]);
46
+ /**
47
+ * Strips forbidden keys from a repository config, recording what was dropped.
48
+ * Rejection is loud rather than silent: the keys land in run warnings so a
49
+ * repository that tries to widen its own permissions is visible.
50
+ */
51
+ export const scrubRepoConfig = (config, pathPrefix = "") => {
52
+ const value = {};
53
+ const rejectedKeys = [];
54
+ for (const [key, entry] of Object.entries(config)) {
55
+ const qualified = pathPrefix ? `${pathPrefix}.${key}` : key;
56
+ if (REPO_FORBIDDEN_KEYS.has(key.toLowerCase())) {
57
+ rejectedKeys.push(qualified);
58
+ continue;
59
+ }
60
+ if (entry && typeof entry === "object" && !Array.isArray(entry)) {
61
+ const nested = scrubRepoConfig(entry, qualified);
62
+ value[key] = nested.value;
63
+ rejectedKeys.push(...nested.rejectedKeys);
64
+ continue;
65
+ }
66
+ value[key] = entry;
67
+ }
68
+ return { value, rejectedKeys };
69
+ };
70
+ const readJsonFile = async (filePath) => {
71
+ if (!existsSync(filePath))
72
+ return undefined;
73
+ try {
74
+ const raw = await readFile(filePath, "utf8");
75
+ const parsed = JSON.parse(raw);
76
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
77
+ ? parsed
78
+ : undefined;
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ };
84
+ const asStringArray = (value) => Array.isArray(value)
85
+ ? value.filter((entry) => typeof entry === "string")
86
+ : undefined;
87
+ const asString = (value) => typeof value === "string" && value.trim() ? value.trim() : undefined;
88
+ const asNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
89
+ const readAgentRoles = (value) => {
90
+ if (!value || typeof value !== "object")
91
+ return undefined;
92
+ const record = value;
93
+ const roles = {
94
+ orchestrator: asString(record.orchestrator),
95
+ worker: asString(record.worker),
96
+ synthesizer: asString(record.synthesizer),
97
+ media: asString(record.media),
98
+ };
99
+ return Object.values(roles).some(Boolean) ? roles : undefined;
100
+ };
101
+ const readLimits = (value) => {
102
+ if (!value || typeof value !== "object")
103
+ return undefined;
104
+ const record = value;
105
+ const limits = {
106
+ maxRounds: asNumber(record.maxRounds ?? record.max_rounds),
107
+ maxToolCalls: asNumber(record.maxToolCalls ?? record.max_tool_calls),
108
+ maxModelCalls: asNumber(record.maxModelCalls ?? record.max_model_calls),
109
+ deadlineMs: asNumber(record.deadlineMs ?? record.deadline_ms),
110
+ };
111
+ return Object.values(limits).some((entry) => entry !== undefined) ? limits : undefined;
112
+ };
113
+ /**
114
+ * Reads MCP server definitions from a *trusted* config layer. Never called on
115
+ * repository config: `scrubRepoConfig` removes the keys first.
116
+ */
117
+ const readMcpServers = (value) => {
118
+ if (!Array.isArray(value))
119
+ return undefined;
120
+ const servers = [];
121
+ for (const entry of value) {
122
+ if (!entry || typeof entry !== "object")
123
+ continue;
124
+ const record = entry;
125
+ const name = asString(record.name);
126
+ if (!name)
127
+ continue;
128
+ const transport = asString(record.transport) ?? (record.command ? "stdio" : "http");
129
+ const common = {
130
+ name,
131
+ enabled: typeof record.enabled === "boolean" ? record.enabled : undefined,
132
+ readOnly: record.readOnly === true || record.read_only === true,
133
+ timeoutMs: asNumber(record.timeoutMs ?? record.timeout_ms),
134
+ allowTools: asStringArray(record.allowTools ?? record.allow_tools),
135
+ denyTools: asStringArray(record.denyTools ?? record.deny_tools),
136
+ };
137
+ if (transport === "stdio") {
138
+ const command = asString(record.command);
139
+ if (!command)
140
+ continue;
141
+ servers.push({
142
+ ...common,
143
+ transport: "stdio",
144
+ command,
145
+ args: asStringArray(record.args),
146
+ cwd: asString(record.cwd),
147
+ env: resolveEnvRefs(record.env),
148
+ });
149
+ continue;
150
+ }
151
+ const url = asString(record.url);
152
+ if (!url)
153
+ continue;
154
+ servers.push({
155
+ ...common,
156
+ transport: "http",
157
+ url,
158
+ headers: resolveEnvRefs(record.headers),
159
+ });
160
+ }
161
+ return servers.length > 0 ? servers : undefined;
162
+ };
163
+ /**
164
+ * Reads HTTP connector declarations from a *trusted* config layer. Credentials
165
+ * are resolved through the same `env:` indirection as MCP servers, so a config
166
+ * file never has to hold a literal secret.
167
+ */
168
+ const readHttpConnectors = (value) => {
169
+ if (!Array.isArray(value))
170
+ return undefined;
171
+ const connectors = [];
172
+ for (const entry of value) {
173
+ if (!entry || typeof entry !== "object")
174
+ continue;
175
+ const record = entry;
176
+ const name = asString(record.name);
177
+ // Base URLs resolve `env:` references too. A site hostname is not secret,
178
+ // but keeping every connector detail in one credentials file beats
179
+ // splitting it across two places for no reason.
180
+ const baseUrl = resolveEnvRef(record.baseUrl ?? record.base_url);
181
+ if (!name || !baseUrl || !Array.isArray(record.tools))
182
+ continue;
183
+ const tools = record.tools
184
+ .filter((tool) => Boolean(tool && typeof tool === "object"))
185
+ .map((tool) => ({
186
+ id: asString(tool.id) ?? "",
187
+ description: asString(tool.description) ?? "",
188
+ method: (asString(tool.method) ?? "GET").toUpperCase(),
189
+ urlTemplate: asString(tool.urlTemplate ?? tool.url_template) ?? "",
190
+ inputSchema: tool.inputSchema,
191
+ responseSelector: asString(tool.responseSelector ?? tool.response_selector),
192
+ maxResponseChars: asNumber(tool.maxResponseChars ?? tool.max_response_chars),
193
+ }))
194
+ .filter((tool) => tool.id && tool.urlTemplate);
195
+ if (tools.length === 0)
196
+ continue;
197
+ const authRecord = record.auth && typeof record.auth === "object"
198
+ ? record.auth
199
+ : undefined;
200
+ connectors.push({
201
+ name,
202
+ baseUrl,
203
+ enabled: typeof record.enabled === "boolean" ? record.enabled : undefined,
204
+ timeoutMs: asNumber(record.timeoutMs ?? record.timeout_ms),
205
+ headers: resolveEnvRefs(record.headers),
206
+ tools,
207
+ auth: authRecord
208
+ ? {
209
+ type: (asString(authRecord.type) ?? "none"),
210
+ token: resolveEnvRef(authRecord.token),
211
+ username: resolveEnvRef(authRecord.username),
212
+ password: resolveEnvRef(authRecord.password),
213
+ headerName: asString(authRecord.headerName ?? authRecord.header_name),
214
+ tokenUrl: resolveEnvRef(authRecord.tokenUrl ?? authRecord.token_url),
215
+ clientId: resolveEnvRef(authRecord.clientId ?? authRecord.client_id),
216
+ refreshToken: resolveEnvRef(authRecord.refreshToken ?? authRecord.refresh_token),
217
+ scope: asString(authRecord.scope),
218
+ }
219
+ : undefined,
220
+ });
221
+ }
222
+ return connectors.length > 0 ? connectors : undefined;
223
+ };
224
+ /**
225
+ * Substitutes `env:NAME` references, including when embedded in a larger
226
+ * string. Header values are the common case — `"Bearer env:GITHUB_TOKEN"` is
227
+ * what anyone would write, and requiring the reference to sit at the start of
228
+ * the value would silently transmit the literal text as a credential.
229
+ *
230
+ * An unresolvable reference yields `undefined` for the whole value rather than
231
+ * a half-substituted string: sending `Bearer env:GITHUB_TOKEN` to an API is
232
+ * worse than sending nothing, because the failure looks like a bad token
233
+ * instead of a missing one.
234
+ */
235
+ const ENV_REF_PATTERN = /env:([A-Za-z_][A-Za-z0-9_]*)/g;
236
+ const substituteEnvRefs = (value) => {
237
+ if (!value.includes("env:"))
238
+ return value;
239
+ let missing = false;
240
+ const output = value.replace(ENV_REF_PATTERN, (_match, name) => {
241
+ const resolved = resolveCredential(name);
242
+ if (resolved === undefined) {
243
+ missing = true;
244
+ return "";
245
+ }
246
+ return resolved;
247
+ });
248
+ return missing ? undefined : output;
249
+ };
250
+ const resolveEnvRef = (value) => {
251
+ if (typeof value !== "string")
252
+ return undefined;
253
+ return substituteEnvRefs(value);
254
+ };
255
+ /**
256
+ * Resolves `env:NAME` references so a config file never has to contain a
257
+ * literal secret. Local-CLI convenience only: an embedded multi-tenant host
258
+ * supplies credentials directly and must not be able to name host env vars.
259
+ */
260
+ const resolveEnvRefs = (value) => {
261
+ if (!value || typeof value !== "object" || Array.isArray(value))
262
+ return undefined;
263
+ const output = {};
264
+ for (const [key, entry] of Object.entries(value)) {
265
+ if (typeof entry !== "string")
266
+ continue;
267
+ // Resolved from the process environment first, then ~/.codali/.creds.
268
+ const resolved = substituteEnvRefs(entry);
269
+ if (resolved !== undefined)
270
+ output[key] = resolved;
271
+ }
272
+ return Object.keys(output).length > 0 ? output : undefined;
273
+ };
274
+ const contextFromConfig = (config) => ({
275
+ agentRoles: readAgentRoles(config.agents ?? config.agent_roles),
276
+ mcpServers: readMcpServers(config.mcpServers ?? config.mcp_servers),
277
+ httpConnectors: readHttpConnectors(config.httpConnectors ?? config.http_connectors),
278
+ limits: readLimits(config.limits),
279
+ allowedTools: asStringArray(config.allowedTools ?? config.allowed_tools),
280
+ deniedTools: asStringArray(config.deniedTools ?? config.denied_tools),
281
+ docdex: (() => {
282
+ const raw = config.docdex;
283
+ if (!raw || typeof raw !== "object")
284
+ return undefined;
285
+ const record = raw;
286
+ return {
287
+ baseUrl: asString(record.baseUrl ?? record.base_url),
288
+ apiKey: asString(record.apiKey ?? record.api_key),
289
+ repoRoot: asString(record.repoRoot ?? record.repo_root),
290
+ repoId: asString(record.repoId ?? record.repo_id),
291
+ allowedOperations: asStringArray(record.allowedOperations ?? record.allowed_operations),
292
+ };
293
+ })(),
294
+ });
295
+ /**
296
+ * Merges a narrower context over a broader one. Allow-lists intersect and
297
+ * deny-lists union, so a later layer can only ever restrict what an earlier one
298
+ * permitted — never widen it.
299
+ */
300
+ export const mergeRunContexts = (base, override) => {
301
+ const allowedTools = base.allowedTools && override.allowedTools
302
+ ? base.allowedTools.filter((tool) => override.allowedTools?.includes(tool))
303
+ : (override.allowedTools ?? base.allowedTools);
304
+ const deniedTools = [
305
+ ...new Set([...(base.deniedTools ?? []), ...(override.deniedTools ?? [])]),
306
+ ];
307
+ const minDefined = (a, b) => {
308
+ if (a === undefined)
309
+ return b;
310
+ if (b === undefined)
311
+ return a;
312
+ return Math.min(a, b);
313
+ };
314
+ return {
315
+ tenant: override.tenant ?? base.tenant,
316
+ repo: { ...base.repo, ...override.repo },
317
+ // Servers come from a trusted layer only; a narrower layer cannot add one.
318
+ mcpServers: override.mcpServers ?? base.mcpServers,
319
+ httpConnectors: override.httpConnectors ?? base.httpConnectors,
320
+ docdex: { ...base.docdex, ...override.docdex },
321
+ agentRoles: { ...base.agentRoles, ...override.agentRoles },
322
+ limits: {
323
+ maxRounds: minDefined(base.limits?.maxRounds, override.limits?.maxRounds),
324
+ maxToolCalls: minDefined(base.limits?.maxToolCalls, override.limits?.maxToolCalls),
325
+ maxModelCalls: minDefined(base.limits?.maxModelCalls, override.limits?.maxModelCalls),
326
+ deadlineMs: minDefined(base.limits?.deadlineMs, override.limits?.deadlineMs),
327
+ },
328
+ allowedTools,
329
+ deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
330
+ warnings: [...(base.warnings ?? []), ...(override.warnings ?? [])],
331
+ };
332
+ };
333
+ /**
334
+ * Resolves run context from trusted user config, then applies the repository's
335
+ * narrowing config on top. Used by the CLI and any single-tenant deployment.
336
+ */
337
+ export class LocalConfigRunContextResolver {
338
+ constructor(options = {}) {
339
+ this.options = options;
340
+ this.id = "local_config";
341
+ }
342
+ async resolve(input) {
343
+ const warnings = [];
344
+ const userDir = this.options.userConfigDir ?? path.join(homedir(), ".codali");
345
+ const userConfig = await readJsonFile(path.join(userDir, "config.json"));
346
+ const base = userConfig ? contextFromConfig(userConfig) : {};
347
+ const repoConfigRaw = await readJsonFile(path.join(input.workspaceRoot, ".codali", "config.json"));
348
+ let repoContext = {};
349
+ if (repoConfigRaw) {
350
+ const scrubbed = scrubRepoConfig(repoConfigRaw);
351
+ if (scrubbed.rejectedKeys.length > 0) {
352
+ warnings.push(`repo_config_keys_rejected:${scrubbed.rejectedKeys.join(",")}`);
353
+ }
354
+ repoContext = contextFromConfig(scrubbed.value);
355
+ }
356
+ const merged = mergeRunContexts(base, repoContext);
357
+ return {
358
+ ...merged,
359
+ tenant: input.tenant ?? merged.tenant,
360
+ repo: { root: input.workspaceRoot, ...merged.repo },
361
+ warnings: [...(merged.warnings ?? []), ...warnings],
362
+ };
363
+ }
364
+ }
365
+ /**
366
+ * Uses context handed over by an embedding host. This is the okacam path: the
367
+ * product resolves the tenant's tools and credentials from its own database and
368
+ * passes them on the request.
369
+ */
370
+ export class ProvidedRunContextResolver {
371
+ constructor() {
372
+ this.id = "provided";
373
+ }
374
+ async resolve(input) {
375
+ if (!input.provided) {
376
+ throw new Error("ProvidedRunContextResolver requires a RunContext on the request.");
377
+ }
378
+ return {
379
+ ...input.provided,
380
+ repo: { root: input.workspaceRoot, ...input.provided.repo },
381
+ tenant: input.tenant ?? input.provided.tenant,
382
+ };
383
+ }
384
+ }
385
+ export const resolveRunContext = async (input, resolver) => {
386
+ const active = resolver ??
387
+ (input.provided ? new ProvidedRunContextResolver() : new LocalConfigRunContextResolver());
388
+ return active.resolve(input);
389
+ };
@@ -1,6 +1,6 @@
1
1
  import { type CodaliStorageObjectPrivacyFlags, type CodaliStorageObjectRef, type CodaliStorageObjectRetentionClass, type CodaliStoragePrivacyClassification, type CodaliStoragePrivacyMetadata } from "./CodaliStorageContracts.js";
2
2
  export type CodaliDatasetPrivacyPurpose = "training" | "export" | "eval" | "replay" | "durable_persistence";
3
- export type CodaliDatasetSecretFindingKind = "sensitive_key" | "bearer_token" | "openai_api_key" | "cloud_access_key" | "github_token" | "jwt" | "private_key" | "env_secret_assignment";
3
+ export type CodaliDatasetSecretFindingKind = "sensitive_key" | "bearer_token" | "openai_api_key" | "cloud_access_key" | "github_token" | "jwt" | "private_key" | "env_secret_assignment" | "connector_api_key";
4
4
  export type CodaliDatasetEligibilityBlockerCode = "secrets_detected" | "privacy_training_not_allowed" | "privacy_export_not_allowed" | "object_training_not_allowed" | "object_export_not_allowed" | "object_eval_not_allowed" | "object_replay_not_allowed" | "retention_do_not_store" | "redaction_required" | "policy_override_requires_admin_audit" | "policy_override_not_requested" | "policy_override_hard_blocked";
5
5
  export interface CodaliDatasetSecretFinding {
6
6
  kind: CodaliDatasetSecretFindingKind;
@@ -1 +1 @@
1
- {"version":3,"file":"CodaliDatasetPrivacyEngine.d.ts","sourceRoot":"","sources":["../../src/storage/CodaliDatasetPrivacyEngine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CodaliDatasetPrivacyEngine.d.ts","sourceRoot":"","sources":["../../src/storage/CodaliDatasetPrivacyEngine.ts"],"names":[],"mappings":"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"}
@@ -30,6 +30,18 @@ const SECRET_VALUE_PATTERNS = [
30
30
  kind: "env_secret_assignment",
31
31
  pattern: /\b(?:API[_-]?KEY|TOKEN|SECRET|PASSWORD|PRIVATE[_-]?KEY)=["']?[^"'\s]{8,}["']?/gi,
32
32
  },
33
+ // Connector credentials. Added alongside the first MCP connector, because
34
+ // that is the point at which third-party secrets first flow through a run.
35
+ // The `sk-` rule above does not match underscore-delimited keys such as
36
+ // mswarm's `sk_prod_mswarm_...`, so those need their own rule.
37
+ {
38
+ kind: "connector_api_key",
39
+ pattern: /\bsk_[A-Za-z0-9]+_[A-Za-z0-9_]{8,}\b/g,
40
+ },
41
+ { kind: "connector_api_key", pattern: /\bglpat-[A-Za-z0-9_-]{16,}\b/g },
42
+ { kind: "connector_api_key", pattern: /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g },
43
+ { kind: "connector_api_key", pattern: /\bAIza[0-9A-Za-z_-]{30,}\b/g },
44
+ { kind: "connector_api_key", pattern: /\bnpm_[A-Za-z0-9]{30,}\b/g },
33
45
  ];
34
46
  const PERSONAL_KEY_PATTERNS = [
35
47
  /(^|[_-])(email|phone|ssn|person|user[_-]?id|requester)([_-]|$)/i,
@@ -1,9 +1,22 @@
1
- import { type ToolContext, type ToolDefinition, type ToolExecutionResult } from "./ToolTypes.js";
1
+ import { type ToolCapability, type ToolContext, type ToolDefinition, type ToolDescriptor, type ToolExecutionResult } from "./ToolTypes.js";
2
+ /**
3
+ * Projects a registered tool into its model-facing descriptor. Kept as a free
4
+ * function so connector adapters can reuse the same defaulting rules.
5
+ */
6
+ export declare const toolDescriptorFor: (tool: ToolDefinition) => ToolDescriptor;
2
7
  export declare class ToolRegistry {
3
8
  private tools;
4
9
  register(tool: ToolDefinition): void;
5
10
  list(): ToolDefinition[];
6
11
  describe(): Array<Pick<ToolDefinition, "name" | "description" | "inputSchema">>;
12
+ /**
13
+ * Model-facing view of the registry, optionally narrowed to a set of tool
14
+ * names. This is derived on every call rather than cached so the planner can
15
+ * never see a schema the executor would not honour.
16
+ */
17
+ catalog(names?: readonly string[]): ToolDescriptor[];
18
+ /** Capability -> tools, for the first stage of two-level tool exposure. */
19
+ capabilities(names?: readonly string[]): Map<ToolCapability, ToolDescriptor[]>;
7
20
  execute(name: string, args: unknown, context: ToolContext): Promise<ToolExecutionResult>;
8
21
  }
9
22
  //# sourceMappingURL=ToolRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,cAAc,EAGnB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AA4QxB,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOpC,IAAI,IAAI,cAAc,EAAE;IAIxB,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAQzE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAkC/F"}
1
+ {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EAGnB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,cAAc,KAAG,cAOvD,CAAC;AA4QH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOpC,IAAI,IAAI,cAAc,EAAE;IAIxB,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAQ/E;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,EAAE;IAOpD,2EAA2E;IAC3E,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAaxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAkC/F"}
@@ -1,4 +1,16 @@
1
- import { ToolExecutionError, toolErrorCategoryForCode, } from "./ToolTypes.js";
1
+ import { ToolExecutionError, toolCapabilityForName, toolErrorCategoryForCode, } from "./ToolTypes.js";
2
+ /**
3
+ * Projects a registered tool into its model-facing descriptor. Kept as a free
4
+ * function so connector adapters can reuse the same defaulting rules.
5
+ */
6
+ export const toolDescriptorFor = (tool) => ({
7
+ name: tool.name,
8
+ description: tool.description,
9
+ inputSchema: tool.inputSchema,
10
+ outputSchema: tool.outputSchema,
11
+ readOnly: tool.readOnly ?? false,
12
+ capability: tool.capability ?? toolCapabilityForName(tool.name),
13
+ });
2
14
  const isObject = (value) => {
3
15
  return typeof value === "object" && value !== null && !Array.isArray(value);
4
16
  };
@@ -262,6 +274,31 @@ export class ToolRegistry {
262
274
  inputSchema: tool.inputSchema,
263
275
  }));
264
276
  }
277
+ /**
278
+ * Model-facing view of the registry, optionally narrowed to a set of tool
279
+ * names. This is derived on every call rather than cached so the planner can
280
+ * never see a schema the executor would not honour.
281
+ */
282
+ catalog(names) {
283
+ const filter = names ? new Set(names) : undefined;
284
+ return this.list()
285
+ .filter((tool) => !filter || filter.has(tool.name))
286
+ .map((tool) => toolDescriptorFor(tool));
287
+ }
288
+ /** Capability -> tools, for the first stage of two-level tool exposure. */
289
+ capabilities(names) {
290
+ const grouped = new Map();
291
+ for (const descriptor of this.catalog(names)) {
292
+ const bucket = grouped.get(descriptor.capability);
293
+ if (bucket) {
294
+ bucket.push(descriptor);
295
+ }
296
+ else {
297
+ grouped.set(descriptor.capability, [descriptor]);
298
+ }
299
+ }
300
+ return grouped;
301
+ }
265
302
  async execute(name, args, context) {
266
303
  const tool = this.tools.get(name);
267
304
  if (!tool) {
@@ -57,10 +57,45 @@ export interface ToolExecutionResult extends ToolHandlerResult {
57
57
  error?: ToolError;
58
58
  }
59
59
  export type ToolHandler = (args: unknown, context: ToolContext) => Promise<ToolHandlerResult>;
60
+ /**
61
+ * Capability group a tool belongs to. The orchestrator selects capabilities
62
+ * first and only then sees the full schemas of the tools inside them, so this
63
+ * value is what keeps the planner prompt bounded as the registry grows.
64
+ */
65
+ export type ToolCapability = string;
60
66
  export interface ToolDefinition {
61
67
  name: string;
62
68
  description: string;
63
69
  inputSchema?: ToolInputSchema;
70
+ /** Shape of `ToolHandlerResult.data`, when the tool returns structured data. */
71
+ outputSchema?: ToolSchemaDefinition;
72
+ /**
73
+ * Whether the tool can mutate anything. Decided by Codali policy, never by a
74
+ * connector's self-description: an MCP server advertising `readOnlyHint` is a
75
+ * hint, not a security boundary.
76
+ */
77
+ readOnly?: boolean;
78
+ capability?: ToolCapability;
64
79
  handler: ToolHandler;
65
80
  }
81
+ /**
82
+ * The model-facing view of a tool. Derived from {@link ToolDefinition} on
83
+ * demand — never stored separately, so the planner and the executor cannot
84
+ * drift onto different schemas.
85
+ */
86
+ export interface ToolDescriptor {
87
+ name: string;
88
+ description: string;
89
+ inputSchema?: ToolInputSchema;
90
+ outputSchema?: ToolSchemaDefinition;
91
+ readOnly: boolean;
92
+ capability: ToolCapability;
93
+ }
94
+ export declare const DEFAULT_TOOL_CAPABILITY = "general";
95
+ /**
96
+ * Capability inferred from a tool name when the definition does not declare
97
+ * one. Names are conventionally `<capability>_<action>` (`docdex_search`) or
98
+ * `<source>:<server>:<tool>` for connector-backed tools.
99
+ */
100
+ export declare const toolCapabilityForName: (name: string) => ToolCapability;
66
101
  //# sourceMappingURL=ToolTypes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolTypes.d.ts","sourceRoot":"","sources":["../../src/tools/ToolTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolTypes.d.ts","sourceRoot":"","sources":["../../src/tools/ToolTypes.ts"],"names":[],"mappings":"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"}
@@ -42,3 +42,24 @@ export const toolErrorCategoryForCode = (code) => {
42
42
  }
43
43
  return "execution";
44
44
  };
45
+ export const DEFAULT_TOOL_CAPABILITY = "general";
46
+ /**
47
+ * Capability inferred from a tool name when the definition does not declare
48
+ * one. Names are conventionally `<capability>_<action>` (`docdex_search`) or
49
+ * `<source>:<server>:<tool>` for connector-backed tools.
50
+ */
51
+ export const toolCapabilityForName = (name) => {
52
+ const trimmed = name.trim();
53
+ if (!trimmed)
54
+ return DEFAULT_TOOL_CAPABILITY;
55
+ const namespaced = trimmed.split(":");
56
+ if (namespaced.length >= 3) {
57
+ // "mcp:github:list_issues" -> "github"
58
+ return namespaced[1] || DEFAULT_TOOL_CAPABILITY;
59
+ }
60
+ const underscored = trimmed.split("_");
61
+ if (underscored.length >= 2 && underscored[0]) {
62
+ return underscored[0];
63
+ }
64
+ return DEFAULT_TOOL_CAPABILITY;
65
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Fitting a tool result into a budget without destroying it.
3
+ *
4
+ * Cutting a serialized payload at a character count leaves the model invalid
5
+ * JSON ending mid-token. Observed with `list_commits`: 12,063 characters cut at
6
+ * 12,000, so the model received a broken document and reported "I can only see
7
+ * one commit" — accurate about what survived, useless as an answer.
8
+ *
9
+ * Most oversized results are a list of similar things. Keeping whole items and
10
+ * saying how many were dropped preserves both validity and the fact that more
11
+ * exists, which is what the model needs to be honest about coverage.
12
+ */
13
+ export interface TruncationResult {
14
+ text: string;
15
+ truncated: boolean;
16
+ /** Items kept, when the payload was a list. */
17
+ keptItems?: number;
18
+ /** Items dropped, when the payload was a list. */
19
+ droppedItems?: number;
20
+ }
21
+ /**
22
+ * Trims a tool result to `limit` characters.
23
+ *
24
+ * When the payload holds a list, drops whole items from the end until it fits,
25
+ * so the result stays parseable. Otherwise falls back to a character cut, which
26
+ * is still better than silence for prose.
27
+ */
28
+ export declare const truncateToolResult: (raw: unknown, serialized: string, limit: number) => TruncationResult;
29
+ //# sourceMappingURL=TruncateResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TruncateResult.d.ts","sourceRoot":"","sources":["../../src/tools/TruncateResult.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAkCD;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC7B,KAAK,OAAO,EACZ,YAAY,MAAM,EAClB,OAAO,MAAM,KACZ,gBA8CF,CAAC"}