@mcoda/codali 0.1.107 → 0.1.109

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 +226 -2
  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 +90 -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 +46 -0
  76. package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
  77. package/dist/gateway/LocalGatewayProvider.js +161 -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 +354 -0
  81. package/dist/gateway/RelevanceJudge.d.ts +14 -0
  82. package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
  83. package/dist/gateway/RelevanceJudge.js +87 -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 +108 -16
  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,161 @@
1
+ import { readFileSync, writeFileSync, existsSync, chmodSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import path from "node:path";
4
+ import { MICROSOFT_GRAPH_SCOPES, microsoftEndpoints, pollForDeviceCodeTokens, startDeviceCode, DeviceCodeError, } from "../connectors/oauth/DeviceCodeAuth.js";
5
+ import { resolveCredential, resetCredentialCache } from "../runcontext/CredentialFile.js";
6
+ /**
7
+ * `codali auth <provider>` — interactive sign-in for connectors that need a
8
+ * user context rather than a static key.
9
+ *
10
+ * The refresh token is written back to `~/.codali/.creds`, which is the same
11
+ * place every other credential lives, so a connector references it as
12
+ * `env:MICROSOFT_REFRESH_TOKEN` exactly like any other secret.
13
+ */
14
+ const CREDS = path.join(homedir(), ".codali", ".creds");
15
+ const HELP = `Usage: codali auth <provider>
16
+
17
+ Providers:
18
+ microsoft Sign in to Microsoft Graph via device code
19
+
20
+ Options:
21
+ --tenant <id> Directory (tenant) ID. Default: $MICROSOFT_TENANT_ID
22
+ --client <id> Application (client) ID. Default: $MICROSOFT_CLIENT_ID
23
+ --scope "<a b c>" Override the requested delegated scopes
24
+ --help, -h Show this help
25
+ `;
26
+ /**
27
+ * Writes a key into the credentials file, replacing any existing entry.
28
+ * Rewrites in place rather than appending, so re-authenticating does not leave
29
+ * a stale token above the new one — the parser takes the last occurrence, and
30
+ * relying on that is a trap.
31
+ */
32
+ export const upsertCredential = (key, value, file = CREDS) => {
33
+ const lines = existsSync(file)
34
+ ? readFileSync(file, "utf8").split(/\r?\n/)
35
+ : ["# Codali credentials. Format: KEY=value", ""];
36
+ let replaced = false;
37
+ const output = lines.map((line) => {
38
+ if (line.startsWith(`${key}=`)) {
39
+ replaced = true;
40
+ return `${key}=${value}`;
41
+ }
42
+ return line;
43
+ });
44
+ if (!replaced) {
45
+ if (output.length > 0 && output[output.length - 1] !== "")
46
+ output.push("");
47
+ output.push(`${key}=${value}`, "");
48
+ }
49
+ writeFileSync(file, output.join("\n"), "utf8");
50
+ chmodSync(file, 0o600);
51
+ };
52
+ const authMicrosoft = async (argv, deps) => {
53
+ const write = deps.write ?? ((line) => process.stdout.write(`${line}\n`));
54
+ resetCredentialCache();
55
+ let tenant = resolveCredential("MICROSOFT_TENANT_ID");
56
+ let client = resolveCredential("MICROSOFT_CLIENT_ID");
57
+ let scope = MICROSOFT_GRAPH_SCOPES;
58
+ for (let index = 0; index < argv.length; index += 1) {
59
+ const arg = argv[index];
60
+ const next = argv[index + 1];
61
+ if (arg === "--tenant" && next) {
62
+ tenant = next;
63
+ index += 1;
64
+ }
65
+ else if (arg === "--client" && next) {
66
+ client = next;
67
+ index += 1;
68
+ }
69
+ else if (arg === "--scope" && next) {
70
+ scope = next;
71
+ index += 1;
72
+ }
73
+ }
74
+ if (!tenant || !client) {
75
+ write("Microsoft sign-in needs a tenant and client id.");
76
+ write("Add MICROSOFT_TENANT_ID and MICROSOFT_CLIENT_ID to ~/.codali/.creds,");
77
+ write("or pass --tenant and --client.");
78
+ return 1;
79
+ }
80
+ const endpoints = microsoftEndpoints(tenant);
81
+ const config = { ...endpoints, clientId: client, scope };
82
+ let start;
83
+ try {
84
+ start = await startDeviceCode(config, deps.fetchImpl);
85
+ }
86
+ catch (error) {
87
+ const detail = error instanceof DeviceCodeError ? error.message : String(error);
88
+ write(`Could not start device sign-in: ${detail}`);
89
+ if (detail.includes("7000218") || detail.toLowerCase().includes("public client")) {
90
+ write("");
91
+ write("The app needs public client flows enabled:");
92
+ write(" Entra portal -> App registrations -> your app -> Authentication");
93
+ write(" -> Advanced settings -> Allow public client flows -> Yes");
94
+ }
95
+ return 1;
96
+ }
97
+ write("");
98
+ write(` Open: ${start.verificationUri}`);
99
+ write(` Code: ${start.userCode}`);
100
+ write("");
101
+ write("Waiting for approval…");
102
+ try {
103
+ const tokens = await pollForDeviceCodeTokens(config, start, deps.fetchImpl, {
104
+ sleep: deps.sleep,
105
+ onPending: () => { },
106
+ });
107
+ if (!tokens.refreshToken) {
108
+ // Without offline_access the grant is good for one hour and then gone,
109
+ // which is not a workflow.
110
+ write("Signed in, but no refresh token was returned.");
111
+ write("The `offline_access` scope is required for a durable session.");
112
+ return 1;
113
+ }
114
+ const file = deps.credsFile ?? CREDS;
115
+ upsertCredential("MICROSOFT_REFRESH_TOKEN", tokens.refreshToken, file);
116
+ upsertCredential("MICROSOFT_TENANT_ID", tenant, file);
117
+ upsertCredential("MICROSOFT_CLIENT_ID", client, file);
118
+ resetCredentialCache();
119
+ write("");
120
+ write("Signed in. Refresh token stored in ~/.codali/.creds");
121
+ if (tokens.scope) {
122
+ write("");
123
+ write("Granted scopes:");
124
+ for (const granted of tokens.scope.split(/\s+/).filter(Boolean)) {
125
+ write(` ${granted}`);
126
+ }
127
+ }
128
+ return 0;
129
+ }
130
+ catch (error) {
131
+ const detail = error instanceof DeviceCodeError ? error.message : String(error);
132
+ write(`Sign-in failed: ${detail}`);
133
+ if (detail.includes("consent") || detail.includes("65001")) {
134
+ write("");
135
+ write("Grant the delegated permissions first:");
136
+ write(" Entra portal -> App registrations -> your app -> API permissions");
137
+ write(" -> Add Microsoft Graph delegated permissions -> Grant admin consent");
138
+ }
139
+ return 1;
140
+ }
141
+ };
142
+ export const runAuth = async (argv, deps = {}) => {
143
+ const write = deps.write ?? ((line) => process.stdout.write(`${line}\n`));
144
+ const [provider, ...rest] = argv;
145
+ if (!provider || argv.includes("--help") || argv.includes("-h")) {
146
+ write(HELP);
147
+ return provider ? 0 : 1;
148
+ }
149
+ if (provider === "microsoft" || provider === "ms" || provider === "graph") {
150
+ return authMicrosoft(rest, deps);
151
+ }
152
+ write(`Unknown auth provider: ${provider}\n\n${HELP}`);
153
+ return 1;
154
+ };
155
+ export const AuthCommand = {
156
+ async run(argv) {
157
+ const exitCode = await runAuth(argv);
158
+ if (exitCode !== 0)
159
+ process.exitCode = exitCode;
160
+ },
161
+ };
@@ -0,0 +1,5 @@
1
+ export declare const runServe: (argv: string[], write?: (line: string) => void) => Promise<number>;
2
+ export declare const ServeCommand: {
3
+ run(argv: string[]): Promise<void>;
4
+ };
5
+ //# sourceMappingURL=ServeCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServeCommand.d.ts","sourceRoot":"","sources":["../../src/cli/ServeCommand.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EAAE,EACd,QAAO,CAAC,IAAI,EAAE,MAAM,KAAK,IAAkD,KAC1E,OAAO,CAAC,MAAM,CA6ChB,CAAC;AAEF,eAAO,MAAM,YAAY;cACP,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAIzC,CAAC"}
@@ -0,0 +1,87 @@
1
+ import path from "node:path";
2
+ import { startCodaliServer } from "../api/CodaliServer.js";
3
+ import { LocalConfigRunContextResolver } from "../runcontext/RunContextResolver.js";
4
+ /**
5
+ * `codali serve` — the local HTTP surface.
6
+ *
7
+ * Single-tenant by design: it authenticates against one operator-supplied key
8
+ * and serves that operator's own configured context. Multi-tenant hosting is a
9
+ * product's job, using {@link createCodaliServer} with its own `authenticate`
10
+ * implementation, because only the product knows how to map a caller to a
11
+ * tenant.
12
+ */
13
+ const HELP = `Usage: codali serve [options]
14
+
15
+ Serve Codali over HTTP with the same result contract the CLI produces.
16
+
17
+ Endpoints:
18
+ POST /v1/chat/completions OpenAI-compatible; carries Codali provenance
19
+ POST /v1/codali/run Canonical Codali request/result
20
+ GET /healthz
21
+
22
+ Options:
23
+ --port <n> Port to listen on (default: 8787)
24
+ --host <addr> Address to bind (default: 127.0.0.1)
25
+ --workspace-root <path> Repository runs resolve against (default: cwd)
26
+ --api-key <key> Required key. Defaults to $CODALI_API_KEY.
27
+ --help, -h Show this help
28
+ `;
29
+ export const runServe = async (argv, write = (line) => process.stdout.write(`${line}\n`)) => {
30
+ if (argv.includes("--help") || argv.includes("-h")) {
31
+ write(HELP);
32
+ return 0;
33
+ }
34
+ let port = 8787;
35
+ let host = "127.0.0.1";
36
+ let workspaceRoot = process.cwd();
37
+ let apiKey = process.env.CODALI_API_KEY;
38
+ for (let index = 0; index < argv.length; index += 1) {
39
+ const arg = argv[index];
40
+ const next = argv[index + 1];
41
+ if (arg === "--port" && next) {
42
+ port = Number.parseInt(next, 10);
43
+ index += 1;
44
+ }
45
+ else if (arg === "--host" && next) {
46
+ host = next;
47
+ index += 1;
48
+ }
49
+ else if (arg === "--workspace-root" && next) {
50
+ workspaceRoot = path.resolve(next);
51
+ index += 1;
52
+ }
53
+ else if (arg === "--api-key" && next) {
54
+ apiKey = next;
55
+ index += 1;
56
+ }
57
+ }
58
+ if (!apiKey) {
59
+ // Refusing to start without a key is deliberate: an unauthenticated server
60
+ // has no tenant, and a run with no tenant scope should not reach
61
+ // connectors or credentials.
62
+ write("codali serve requires an API key. Set CODALI_API_KEY or pass --api-key.");
63
+ return 1;
64
+ }
65
+ const context = await new LocalConfigRunContextResolver().resolve({ workspaceRoot });
66
+ const principal = {
67
+ tenant: { id: "local", slug: "local" },
68
+ runContext: context,
69
+ };
70
+ const { port: boundPort } = await startCodaliServer({
71
+ port,
72
+ host,
73
+ workspaceRoot,
74
+ authenticate: async (candidate) => (candidate === apiKey ? principal : undefined),
75
+ });
76
+ write(`codali serve listening on http://${host}:${boundPort}`);
77
+ write(" POST /v1/chat/completions");
78
+ write(" POST /v1/codali/run");
79
+ return 0;
80
+ };
81
+ export const ServeCommand = {
82
+ async run(argv) {
83
+ const exitCode = await runServe(argv);
84
+ if (exitCode !== 0)
85
+ process.exitCode = exitCode;
86
+ },
87
+ };
@@ -0,0 +1,22 @@
1
+ import { attachMcpTools } from "../connectors/mcp/McpToolSource.js";
2
+ import type { RunContext } from "../runcontext/RunContextResolver.js";
3
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
4
+ export interface ToolsOptions {
5
+ command: "list" | "describe" | "call" | "health";
6
+ target?: string;
7
+ workspaceRoot: string;
8
+ argsJson?: string;
9
+ json: boolean;
10
+ }
11
+ export declare const parseToolsArgs: (argv: string[]) => ToolsOptions;
12
+ export interface ToolsDependencies {
13
+ resolveRunContext?: (workspaceRoot: string) => Promise<RunContext>;
14
+ buildBaseRegistry?: (context: RunContext, workspaceRoot: string) => ToolRegistry;
15
+ attachMcp?: typeof attachMcpTools;
16
+ write?: (line: string) => void;
17
+ }
18
+ export declare const runTools: (argv: string[], deps?: ToolsDependencies) => Promise<number>;
19
+ export declare const ToolsCommand: {
20
+ run(argv: string[]): Promise<void>;
21
+ };
22
+ //# sourceMappingURL=ToolsCommand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolsCommand.d.ts","sourceRoot":"","sources":["../../src/cli/ToolsCommand.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AA2BxD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,EAAE,KAAG,YAiC/C,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACnE,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,KAAK,YAAY,CAAC;IACjF,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;IAClC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAkBD,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EAAE,EACd,OAAM,iBAAsB,KAC3B,OAAO,CAAC,MAAM,CA8IhB,CAAC;AAEF,eAAO,MAAM,YAAY;cACP,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAIzC,CAAC"}
@@ -0,0 +1,208 @@
1
+ import path from "node:path";
2
+ import { attachHttpTools } from "../connectors/http/HttpToolSource.js";
3
+ import { attachMcpTools } from "../connectors/mcp/McpToolSource.js";
4
+ import { DocdexClient } from "../docdex/DocdexClient.js";
5
+ import { LocalConfigRunContextResolver } from "../runcontext/RunContextResolver.js";
6
+ import { ToolRegistry } from "../tools/ToolRegistry.js";
7
+ import { createDocdexTools } from "../tools/docdex/DocdexTools.js";
8
+ import { sanitizeArgs } from "../gateway/GatewayTracer.js";
9
+ /**
10
+ * `codali tools` — inspect what an orchestration run can actually reach.
11
+ *
12
+ * Without this the only way to find out which tools a configured MCP server
13
+ * exposes is to ask a question and read the trace, which conflates connector
14
+ * problems with planning problems.
15
+ */
16
+ const HELP = `Usage: codali tools <list|describe|call|health> [options]
17
+
18
+ Commands:
19
+ list List every tool available to a run, grouped by capability
20
+ describe <name> Show one tool's description and argument schema
21
+ call <name> Invoke a tool directly (read-only connectors)
22
+ health Show MCP server connection status
23
+
24
+ Options:
25
+ --workspace-root <path> Repository to resolve config against (default: cwd)
26
+ --args-json <json> Arguments for "call"
27
+ --json Machine-readable output
28
+ --help, -h Show this help
29
+ `;
30
+ export const parseToolsArgs = (argv) => {
31
+ const [rawCommand, ...rest] = argv;
32
+ const command = rawCommand;
33
+ if (!["list", "describe", "call", "health"].includes(command)) {
34
+ throw new Error(`Unknown tools command: ${rawCommand ?? "(none)"}\n\n${HELP}`);
35
+ }
36
+ let workspaceRoot = process.cwd();
37
+ let argsJson;
38
+ let json = false;
39
+ let target;
40
+ for (let index = 0; index < rest.length; index += 1) {
41
+ const arg = rest[index];
42
+ const next = rest[index + 1];
43
+ if (arg === "--workspace-root" && next) {
44
+ workspaceRoot = path.resolve(next);
45
+ index += 1;
46
+ }
47
+ else if (arg === "--args-json" && next) {
48
+ argsJson = next;
49
+ index += 1;
50
+ }
51
+ else if (arg === "--json") {
52
+ json = true;
53
+ }
54
+ else if (arg && !arg.startsWith("--") && !target) {
55
+ target = arg;
56
+ }
57
+ }
58
+ if ((command === "describe" || command === "call") && !target) {
59
+ throw new Error(`codali tools ${command} requires a tool name.\n\n${HELP}`);
60
+ }
61
+ return { command, target, workspaceRoot, argsJson, json };
62
+ };
63
+ const buildBaseRegistryDefault = (context, workspaceRoot) => {
64
+ const registry = new ToolRegistry();
65
+ const client = new DocdexClient({
66
+ baseUrl: context.docdex?.baseUrl ?? "http://127.0.0.1:28491",
67
+ repoRoot: context.repo?.root ?? workspaceRoot,
68
+ repoId: context.docdex?.repoId,
69
+ apiKey: context.docdex?.apiKey,
70
+ allowedOperations: context.docdex?.allowedOperations,
71
+ });
72
+ for (const tool of createDocdexTools(client))
73
+ registry.register(tool);
74
+ return registry;
75
+ };
76
+ export const runTools = async (argv, deps = {}) => {
77
+ const write = deps.write ?? ((line) => process.stdout.write(`${line}\n`));
78
+ if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
79
+ write(HELP);
80
+ return 0;
81
+ }
82
+ const options = parseToolsArgs(argv);
83
+ const context = deps.resolveRunContext
84
+ ? await deps.resolveRunContext(options.workspaceRoot)
85
+ : await new LocalConfigRunContextResolver().resolve({
86
+ workspaceRoot: options.workspaceRoot,
87
+ });
88
+ const registry = (deps.buildBaseRegistry ?? buildBaseRegistryDefault)(context, options.workspaceRoot);
89
+ const mcp = await (deps.attachMcp ?? attachMcpTools)({
90
+ context,
91
+ toolRegistry: registry,
92
+ });
93
+ // Hand-declared HTTP connectors are part of the same catalog; omitting them
94
+ // here would make `tools list` disagree with what a run can actually reach.
95
+ const http = attachHttpTools({ context, toolRegistry: registry });
96
+ mcp.warnings.push(...http.warnings);
97
+ try {
98
+ if (options.command === "health") {
99
+ if (options.json) {
100
+ write(JSON.stringify({ servers: mcp.health, warnings: mcp.warnings }, null, 2));
101
+ }
102
+ else if (mcp.health.length === 0) {
103
+ write("No MCP servers configured.");
104
+ write("Add them under \"mcpServers\" in ~/.codali/config.json.");
105
+ }
106
+ else {
107
+ for (const server of mcp.health) {
108
+ const detail = server.status === "connected"
109
+ ? `${server.toolCount} tool(s), ${server.discoveryMs ?? 0}ms`
110
+ : (server.error ?? server.status);
111
+ write(`${server.status === "connected" ? "ok " : "FAIL"} ${server.name} ${detail}`);
112
+ }
113
+ }
114
+ return mcp.health.some((server) => server.status === "failed") ? 1 : 0;
115
+ }
116
+ if (options.command === "list") {
117
+ const capabilities = registry.capabilities();
118
+ if (options.json) {
119
+ write(JSON.stringify(registry.catalog(), null, 2));
120
+ return 0;
121
+ }
122
+ if (capabilities.size === 0) {
123
+ write("No tools available.");
124
+ return 0;
125
+ }
126
+ for (const [capability, tools] of [...capabilities.entries()].sort(([a], [b]) => a.localeCompare(b))) {
127
+ write(`${capability} (${tools.length})`);
128
+ for (const tool of tools.sort((a, b) => a.name.localeCompare(b.name))) {
129
+ const flag = tool.readOnly ? "" : " [write]";
130
+ write(` ${tool.name}${flag}`);
131
+ write(` ${tool.description}`);
132
+ }
133
+ write("");
134
+ }
135
+ for (const warning of mcp.warnings)
136
+ write(`warning: ${warning}`);
137
+ return 0;
138
+ }
139
+ if (options.command === "describe") {
140
+ const descriptor = registry.catalog([options.target])[0];
141
+ if (!descriptor) {
142
+ write(`Unknown tool: ${options.target}`);
143
+ return 1;
144
+ }
145
+ if (options.json) {
146
+ write(JSON.stringify(descriptor, null, 2));
147
+ return 0;
148
+ }
149
+ write(descriptor.name);
150
+ write(` capability: ${descriptor.capability}`);
151
+ write(` read-only: ${descriptor.readOnly}`);
152
+ write(` ${descriptor.description}`);
153
+ if (descriptor.inputSchema) {
154
+ write(" input schema:");
155
+ write(JSON.stringify(descriptor.inputSchema, null, 2)
156
+ .split("\n")
157
+ .map((line) => ` ${line}`)
158
+ .join("\n"));
159
+ }
160
+ return 0;
161
+ }
162
+ // call
163
+ const descriptor = registry.catalog([options.target])[0];
164
+ if (!descriptor) {
165
+ write(`Unknown tool: ${options.target}`);
166
+ return 1;
167
+ }
168
+ if (!descriptor.readOnly) {
169
+ // Phase 2 connectors are read-only by policy; a direct invocation must
170
+ // not be the way around that.
171
+ write(`Refusing to call ${descriptor.name}: it is not marked read-only.`);
172
+ return 1;
173
+ }
174
+ const args = options.argsJson ? JSON.parse(options.argsJson) : {};
175
+ const result = await registry.execute(descriptor.name, args, {
176
+ workspaceRoot: options.workspaceRoot,
177
+ allowShell: false,
178
+ allowDestructiveOperations: false,
179
+ allowOutsideWorkspace: false,
180
+ });
181
+ if (options.json) {
182
+ write(JSON.stringify({
183
+ ok: result.ok,
184
+ output: result.output,
185
+ error: result.error,
186
+ args: sanitizeArgs(args),
187
+ }, null, 2));
188
+ }
189
+ else if (result.ok) {
190
+ write(result.output);
191
+ }
192
+ else {
193
+ write(`Tool failed (${result.error?.code}): ${result.error?.message}`);
194
+ }
195
+ return result.ok ? 0 : 1;
196
+ }
197
+ finally {
198
+ // stdio servers are child processes; leaving them running would orphan them.
199
+ await mcp.registry?.close();
200
+ }
201
+ };
202
+ export const ToolsCommand = {
203
+ async run(argv) {
204
+ const exitCode = await runTools(argv);
205
+ if (exitCode !== 0)
206
+ process.exitCode = exitCode;
207
+ },
208
+ };
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA0EA,eAAO,MAAM,MAAM,GAAU,OAAM,MAAM,EAA0B,KAAG,OAAO,CAAC,IAAI,CA8CjF,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAsFA,eAAO,MAAM,MAAM,GAAU,OAAM,MAAM,EAA0B,KAAG,OAAO,CAAC,IAAI,CAkEjF,CAAC"}
package/dist/cli.js CHANGED
@@ -2,12 +2,20 @@
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
+ import { AskCommand } from "./cli/AskCommand.js";
5
6
  import { RunCommand } from "./cli/RunCommand.js";
7
+ import { ToolsCommand } from "./cli/ToolsCommand.js";
8
+ import { ServeCommand } from "./cli/ServeCommand.js";
9
+ import { AuthCommand } from "./cli/AuthCommand.js";
6
10
  import { FeedbackCommand } from "./cli/FeedbackCommand.js";
7
11
  import { EvalCommand } from "./cli/EvalCommand.js";
8
12
  import { DatasetCommand } from "./cli/DatasetCommand.js";
9
13
  import { ImprovementCommand } from "./cli/ImprovementCommand.js";
10
- const HELP_TEXT = "Usage: codali run [--workspace-root <path>] --agent <slug> [--task <file>]\n" +
14
+ const HELP_TEXT = "Usage: codali ask \"<question>\" [--trace] [--json] [--workspace-root <path>]\n" +
15
+ " or: codali tools <list|describe|call|health> [options]\n" +
16
+ " or: codali auth <microsoft>\n" +
17
+ " or: codali serve [--port <n>] [--api-key <key>]\n" +
18
+ " or: codali run [--workspace-root <path>] --agent <slug> [--task <file>]\n" +
11
19
  " or: codali run [--workspace-root <path>] --provider <name> --model <model> [--task <file>]\n" +
12
20
  " or: codali <fix|review|explain|test> [run options] [--task <file>]\n" +
13
21
  " or: codali eval --suite <path> [eval options]\n" +
@@ -18,6 +26,10 @@ const HELP_TEXT = "Usage: codali run [--workspace-root <path>] --agent <slug> [-
18
26
  " or: codali learn --confirm <dedupe_key> [--confirm <dedupe_key> ...]\n" +
19
27
  "\n" +
20
28
  "Commands:\n" +
29
+ " ask Ask a question. Routes, gathers evidence with tools, answers with citations.\n" +
30
+ " tools Inspect the tools a run can reach, including MCP servers.\n" +
31
+ " auth Sign in to a connector that needs a user context (Microsoft Graph).\n" +
32
+ " serve Serve Codali over HTTP with the same contract as the CLI.\n" +
21
33
  " run Run a single task (advanced/general profile).\n" +
22
34
  " fix Apply fix workflow profile (patch-focused output).\n" +
23
35
  " review Apply review workflow profile (findings-focused output).\n" +
@@ -83,6 +95,22 @@ export const runCli = async (argv = process.argv.slice(2)) => {
83
95
  printDoctor();
84
96
  return;
85
97
  }
98
+ if (command === "ask") {
99
+ await AskCommand.run(rest);
100
+ return;
101
+ }
102
+ if (command === "auth") {
103
+ await AuthCommand.run(rest);
104
+ return;
105
+ }
106
+ if (command === "serve") {
107
+ await ServeCommand.run(rest);
108
+ return;
109
+ }
110
+ if (command === "tools" || command === "mcp") {
111
+ await ToolsCommand.run(command === "mcp" ? ["health", ...rest] : rest);
112
+ return;
113
+ }
86
114
  if (["run", "fix", "review", "explain", "test"].includes(command)) {
87
115
  await RunCommand.run(["--command", command, ...rest]);
88
116
  return;
@@ -0,0 +1,74 @@
1
+ import type { ToolDefinition, ToolInputSchema } from "../../tools/ToolTypes.js";
2
+ /**
3
+ * Hand-declared HTTP tools.
4
+ *
5
+ * Deliberately *not* a generic OpenAPI compiler. Importing an arbitrary spec
6
+ * drags in hundreds of irrelevant operations, several authentication styles,
7
+ * inconsistent pagination, enormous nested schemas, and write operations that
8
+ * have no business being reachable — and then the orchestrator has to choose
9
+ * among them. A Jira, CRM, or Graph lookup is three lines of declaration; an
10
+ * offline importer is worth building only once maintaining those declarations
11
+ * across several real connectors proves burdensome.
12
+ *
13
+ * Everything here is read-only by construction: the method allowlist rejects
14
+ * anything that mutates.
15
+ */
16
+ export type HttpToolMethod = "GET" | "HEAD";
17
+ export interface HttpConnectorAuth {
18
+ type: "bearer" | "basic" | "header" | "none" | "oauth2_refresh";
19
+ /** Resolved value. Never a reference — resolution happens before this point. */
20
+ token?: string;
21
+ username?: string;
22
+ password?: string;
23
+ headerName?: string;
24
+ /** oauth2_refresh only: exchanges a stored refresh token for an access token. */
25
+ tokenUrl?: string;
26
+ clientId?: string;
27
+ refreshToken?: string;
28
+ scope?: string;
29
+ }
30
+ export declare const resetAccessTokenCache: () => void;
31
+ export interface HttpToolDeclaration {
32
+ id: string;
33
+ description: string;
34
+ method: HttpToolMethod;
35
+ /** e.g. `/rest/api/3/issue/{issueKey}` — `{name}` is substituted from args. */
36
+ urlTemplate: string;
37
+ inputSchema?: ToolInputSchema;
38
+ /**
39
+ * Dotted path into the response, e.g. `issues[].fields.summary`. Applied
40
+ * before the result reaches a model, because a raw API payload routinely
41
+ * exceeds an entire evidence budget.
42
+ */
43
+ responseSelector?: string;
44
+ /** Cap on serialized response characters. */
45
+ maxResponseChars?: number;
46
+ }
47
+ export interface HttpConnectorDefinition {
48
+ name: string;
49
+ baseUrl: string;
50
+ auth?: HttpConnectorAuth;
51
+ headers?: Record<string, string>;
52
+ timeoutMs?: number;
53
+ tools: HttpToolDeclaration[];
54
+ enabled?: boolean;
55
+ }
56
+ /**
57
+ * Substitutes `{name}` placeholders and appends anything left over as query
58
+ * parameters. Placeholder values are URL-encoded, so a model cannot inject a
59
+ * path segment or escape the connector's base URL.
60
+ */
61
+ export declare const buildHttpUrl: (baseUrl: string, template: string, args: Record<string, unknown>) => string;
62
+ /**
63
+ * Projects a response down to what was asked for. `items[].name` maps over an
64
+ * array; a plain dotted path drills in.
65
+ */
66
+ export declare const applyResponseSelector: (payload: unknown, selector?: string) => unknown;
67
+ export interface HttpToolFactoryOptions {
68
+ connector: HttpConnectorDefinition;
69
+ fetchImpl?: typeof fetch;
70
+ }
71
+ export declare const httpToolName: (connector: string, tool: string) => string;
72
+ export declare const httpToolToDefinition: (declaration: HttpToolDeclaration, options: HttpToolFactoryOptions) => ToolDefinition;
73
+ export declare const httpConnectorToDefinitions: (options: HttpToolFactoryOptions) => ToolDefinition[];
74
+ //# sourceMappingURL=HttpToolDefinition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HttpToolDefinition.d.ts","sourceRoot":"","sources":["../../../src/connectors/http/HttpToolDefinition.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhF;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAChE,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAYD,eAAO,MAAM,qBAAqB,QAAO,IAAgC,CAAC;AAwC1E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAcD;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,MAqBF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,OAAO,EAAE,WAAW,MAAM,KAAG,OAoB3E,CAAC;AAsBF,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,uBAAuB,CAAC;IACnC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,eAAO,MAAM,YAAY,GAAI,WAAW,MAAM,EAAE,MAAM,MAAM,KAAG,MAClC,CAAC;AAE9B,eAAO,MAAM,oBAAoB,GAC/B,aAAa,mBAAmB,EAChC,SAAS,sBAAsB,KAC9B,cA6FF,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,SAAS,sBAAsB,KAC9B,cAAc,EAIkC,CAAC"}