@a3t/rapid-core 0.1.12 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +138 -10
- package/dist/index.js +325 -7
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,14 @@ interface RapidConfig {
|
|
|
10
10
|
agents: AgentsConfig;
|
|
11
11
|
context?: ContextConfig;
|
|
12
12
|
mcp?: McpConfig;
|
|
13
|
+
lima?: LimaConfig;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Lima VM configuration
|
|
17
|
+
*/
|
|
18
|
+
interface LimaConfig {
|
|
19
|
+
/** Install GitHub CLI (gh) in the VM (default: true) */
|
|
20
|
+
installGh?: boolean;
|
|
13
21
|
}
|
|
14
22
|
interface ContainerConfig {
|
|
15
23
|
devcontainer?: string;
|
|
@@ -90,14 +98,26 @@ interface McpConfig {
|
|
|
90
98
|
configFile?: string;
|
|
91
99
|
servers?: Record<string, McpServerConfig>;
|
|
92
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* MCP transport types following the MCP specification.
|
|
103
|
+
* - 'stdio': Local subprocess communication (MCP spec standard)
|
|
104
|
+
* - 'streamable-http': Remote HTTP communication (MCP spec standard, replaces deprecated SSE)
|
|
105
|
+
* - 'remote': Alias for 'streamable-http' (user-friendly, backwards compatible)
|
|
106
|
+
*/
|
|
107
|
+
type McpTransportType = 'stdio' | 'streamable-http' | 'remote';
|
|
93
108
|
interface McpServerConfig {
|
|
94
109
|
/** Enable this MCP server (default: true) */
|
|
95
110
|
enabled?: boolean;
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Server transport type (MCP spec naming):
|
|
113
|
+
* - 'stdio': Local subprocess (command + args)
|
|
114
|
+
* - 'streamable-http': Remote HTTP server (url + headers)
|
|
115
|
+
* - 'remote': Alias for 'streamable-http' (backwards compatible)
|
|
116
|
+
*/
|
|
117
|
+
type?: McpTransportType;
|
|
118
|
+
/** URL for remote/streamable-http servers */
|
|
99
119
|
url?: string;
|
|
100
|
-
/** HTTP headers for remote servers */
|
|
120
|
+
/** HTTP headers for remote/streamable-http servers */
|
|
101
121
|
headers?: Record<string, string>;
|
|
102
122
|
/** Command for stdio servers */
|
|
103
123
|
command?: string;
|
|
@@ -212,6 +232,8 @@ declare function buildAgentArgs(agent: AgentDefinition, options?: {
|
|
|
212
232
|
compactPrompt?: boolean;
|
|
213
233
|
/** Custom system prompt to use instead of default RAPID methodology */
|
|
214
234
|
customPrompt?: string;
|
|
235
|
+
/** Additional context content to append to the system prompt */
|
|
236
|
+
contextContent?: string;
|
|
215
237
|
}): string[];
|
|
216
238
|
/**
|
|
217
239
|
* Check if an agent reads instruction files from the filesystem.
|
|
@@ -639,7 +661,7 @@ declare function getSecretReferences(templateNames: string[]): Record<string, st
|
|
|
639
661
|
*/
|
|
640
662
|
interface McpServerDefinition extends McpServerConfig {
|
|
641
663
|
enabled?: boolean;
|
|
642
|
-
type?: 'remote' | 'stdio';
|
|
664
|
+
type?: 'remote' | 'stdio' | 'streamable-http';
|
|
643
665
|
url?: string;
|
|
644
666
|
headers?: Record<string, string>;
|
|
645
667
|
command?: string;
|
|
@@ -648,6 +670,7 @@ interface McpServerDefinition extends McpServerConfig {
|
|
|
648
670
|
}
|
|
649
671
|
/**
|
|
650
672
|
* MCP server info for display
|
|
673
|
+
* Note: 'streamable-http' is normalized to 'remote' for display purposes
|
|
651
674
|
*/
|
|
652
675
|
interface McpServerInfo {
|
|
653
676
|
name: string;
|
|
@@ -691,10 +714,11 @@ interface OpenCodeConfig {
|
|
|
691
714
|
instructions?: string[];
|
|
692
715
|
}
|
|
693
716
|
/**
|
|
694
|
-
* OpenCode MCP entry format
|
|
717
|
+
* OpenCode MCP entry format.
|
|
718
|
+
* OpenCode uses 'local' for stdio and 'remote' for HTTP servers.
|
|
695
719
|
*/
|
|
696
720
|
interface OpenCodeMcpEntry {
|
|
697
|
-
type: '
|
|
721
|
+
type: 'local' | 'remote';
|
|
698
722
|
url?: string | undefined;
|
|
699
723
|
headers?: Record<string, string> | undefined;
|
|
700
724
|
command?: string | undefined;
|
|
@@ -730,11 +754,22 @@ declare function enableMcpServer(config: RapidConfig, name: string): RapidConfig
|
|
|
730
754
|
*/
|
|
731
755
|
declare function disableMcpServer(config: RapidConfig, name: string): RapidConfig;
|
|
732
756
|
/**
|
|
733
|
-
* Generate .mcp.json config from rapid.json mcp section
|
|
757
|
+
* Generate .mcp.json config from rapid.json mcp section.
|
|
758
|
+
*
|
|
759
|
+
* Output format follows Claude Code conventions:
|
|
760
|
+
* - 'stdio' servers use type: 'stdio' with command/args/env
|
|
761
|
+
* - Remote servers (type: 'remote' or 'streamable-http') use type: 'http' with url/headers
|
|
762
|
+
*
|
|
763
|
+
* Note: Claude Code uses 'http' instead of MCP spec's 'streamable-http' for simplicity.
|
|
734
764
|
*/
|
|
735
765
|
declare function generateMcpConfig(config: RapidConfig): GeneratedMcpConfig;
|
|
736
766
|
/**
|
|
737
|
-
* Generate opencode.json config format
|
|
767
|
+
* Generate opencode.json config format.
|
|
768
|
+
*
|
|
769
|
+
* Output format follows OpenCode conventions:
|
|
770
|
+
* - 'stdio' servers use type: 'local' with command/args/env
|
|
771
|
+
* - Remote servers (type: 'remote' or 'streamable-http') use type: 'remote' with url/headers
|
|
772
|
+
* - Environment variables use {env:VAR} format instead of ${VAR}
|
|
738
773
|
*/
|
|
739
774
|
declare function generateOpenCodeConfig(config: RapidConfig): OpenCodeConfig;
|
|
740
775
|
/**
|
|
@@ -758,4 +793,97 @@ declare function readMcpConfig(rootDir: string, config?: RapidConfig): Promise<G
|
|
|
758
793
|
*/
|
|
759
794
|
declare function getMcpConfigPath(rootDir: string, config?: RapidConfig): string;
|
|
760
795
|
|
|
761
|
-
|
|
796
|
+
/**
|
|
797
|
+
* JSON formatting utilities using Prettier
|
|
798
|
+
*/
|
|
799
|
+
/**
|
|
800
|
+
* Format JSON using Prettier for consistent output
|
|
801
|
+
* @param data - The data to format as JSON
|
|
802
|
+
* @returns Formatted JSON string with trailing newline
|
|
803
|
+
*/
|
|
804
|
+
declare function formatJson(data: unknown): Promise<string>;
|
|
805
|
+
/**
|
|
806
|
+
* Synchronous JSON formatting (fallback to JSON.stringify if prettier fails)
|
|
807
|
+
* @param data - The data to format as JSON
|
|
808
|
+
* @returns Formatted JSON string with trailing newline
|
|
809
|
+
*/
|
|
810
|
+
declare function formatJsonSync(data: unknown): string;
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Context file assembly for AI agents
|
|
814
|
+
*
|
|
815
|
+
* Reads and assembles context from files and directories specified in rapid.json,
|
|
816
|
+
* then formats it for injection into agent system prompts.
|
|
817
|
+
*/
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Result of reading a context file
|
|
821
|
+
*/
|
|
822
|
+
interface ContextFileResult {
|
|
823
|
+
path: string;
|
|
824
|
+
relativePath: string;
|
|
825
|
+
content: string;
|
|
826
|
+
size: number;
|
|
827
|
+
truncated: boolean;
|
|
828
|
+
}
|
|
829
|
+
/**
|
|
830
|
+
* Information about a skipped file
|
|
831
|
+
*/
|
|
832
|
+
interface SkippedFile {
|
|
833
|
+
path: string;
|
|
834
|
+
reason: 'missing' | 'binary' | 'too-large' | 'excluded' | 'directory' | 'error';
|
|
835
|
+
error?: string;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Result of assembling all context files
|
|
839
|
+
*/
|
|
840
|
+
interface AssembledContext {
|
|
841
|
+
files: ContextFileResult[];
|
|
842
|
+
totalSize: number;
|
|
843
|
+
skippedFiles: SkippedFile[];
|
|
844
|
+
content: string;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Options for context assembly
|
|
848
|
+
*/
|
|
849
|
+
interface ContextAssemblyOptions {
|
|
850
|
+
/** Maximum size per file in bytes (default: 100KB) */
|
|
851
|
+
maxFileSize?: number;
|
|
852
|
+
/** Maximum total size in bytes (default: 500KB) */
|
|
853
|
+
maxTotalSize?: number;
|
|
854
|
+
/** Whether to include file headers with paths (default: true) */
|
|
855
|
+
includeHeaders?: boolean;
|
|
856
|
+
/** File extensions to treat as binary (in addition to built-in list) */
|
|
857
|
+
binaryExtensions?: string[];
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Check if a file path matches any exclude patterns
|
|
861
|
+
*/
|
|
862
|
+
declare function matchesExcludePattern(relativePath: string, excludePatterns: string[]): boolean;
|
|
863
|
+
/**
|
|
864
|
+
* Check if a file is likely binary based on extension
|
|
865
|
+
*/
|
|
866
|
+
declare function isBinaryFile(filepath: string, additionalExtensions?: string[]): boolean;
|
|
867
|
+
/**
|
|
868
|
+
* Read a single context file with safety checks
|
|
869
|
+
*/
|
|
870
|
+
declare function readContextFile(filepath: string, rootDir: string, options?: ContextAssemblyOptions): Promise<ContextFileResult | SkippedFile>;
|
|
871
|
+
/**
|
|
872
|
+
* Recursively read files from a directory
|
|
873
|
+
*/
|
|
874
|
+
declare function readContextDirectory(dirPath: string, rootDir: string, excludePatterns: string[], options?: ContextAssemblyOptions): Promise<{
|
|
875
|
+
files: ContextFileResult[];
|
|
876
|
+
skipped: SkippedFile[];
|
|
877
|
+
}>;
|
|
878
|
+
/**
|
|
879
|
+
* Assemble all context files from configuration
|
|
880
|
+
*/
|
|
881
|
+
declare function assembleContext(rootDir: string, config: ContextConfig, options?: ContextAssemblyOptions): Promise<AssembledContext>;
|
|
882
|
+
/**
|
|
883
|
+
* Format assembled context as a string for injection
|
|
884
|
+
*/
|
|
885
|
+
declare function formatContextContent(files: ContextFileResult[], options?: {
|
|
886
|
+
includeHeaders?: boolean;
|
|
887
|
+
}): string;
|
|
888
|
+
|
|
889
|
+
export { type AgentDefinition, type AgentStatus, type AgentsConfig, type AssembledContext, type AuthStatus, CODE_EDITING_GUIDELINES, COMMUNICATION_GUIDELINES, type ContainerConfig, type ContainerStatus, type ContextAssemblyOptions, type ContextConfig, type ContextFileResult, DEBUGGING_GUIDELINES, type DetectedCredential, type DevcontainerConfig, type DotenvConfig, type EnvironmentStatus, type EnvrcConfig, type ExternalAuthConfig, type ExternalAuthSource, GIT_GUIDELINES, type GeneratedMcpConfig, type LoadedConfig, type LogLevel, MCP_SERVER_TEMPLATES, MCP_USAGE_GUIDELINES, type McpConfig, type McpServerConfig, type McpServerDefinition, type McpServerEntry, type McpServerInfo, type McpServerStatus, type McpServerTemplate, type McpTransportType, type OpAuthStatus, type OpenCodeConfig, type OpenCodeMcpEntry, RAPID_METHODOLOGY, RAPID_METHODOLOGY_COMPACT, RAPID_PHASES, type RapidConfig, type RapidPhase, type SecretStatus, type SecretsConfig, type SecretsStatus, type SkippedFile, addMcpServer, addMcpServerFromTemplate, agentReadsInstructionFiles, agentSupportsRuntimeInjection, assembleContext, buildAgentArgs, checkAgentAvailable, checkAllAgents, detectAiderAuth, detectAllCredentials, detectClaudeCodeAuth, detectCodexAuth, detectEnvAuth, detectGeminiAuth, disableMcpServer, enableMcpServer, execInContainer, formatAuthStatus, formatContextContent, formatJson, formatJsonSync, generateEnvrc, generateFullSystemPrompt, generateMcpConfig, generateOpenCodeConfig, generateRapidMethodology, getAgent, getAuthEnvironment, getAuthStatus, getContainerName, getContainerStatus, getCredentialsForProvider, getDefaultAgent, getDefaultConfig, getDevcontainerPath, getEasySetupTemplates, getLogLevel, getMcpConfigPath, getMcpServerStatus, getMcpServers, getMcpTemplate, getMcpTemplateNames, getOpAuthStatus, getProviderInfo, getRequiredSecrets, getSecretReferences, getStandardAgentInstructions, hasDevcontainerCli, hasDocker, hasEnvrc, hasMcpConfig, hasOpCli, hasOpServiceAccountToken, hasVaultCli, isBinaryFile, isOpAuthenticated, isVaultAuthenticated, launchAgent, loadConfig, loadConfigFromFile, loadDevcontainerConfig, loadSecrets, logger, matchesExcludePattern, mergeWithDefaults, readContextDirectory, readContextFile, readEnvrc, readMcpConfig, readOpSecret, readVaultSecret, removeMcpServer, setLogLevel, startContainer, stopContainer, verifySecret, verifySecrets, writeEnvrc, writeMcpConfig, writeOpenCodeConfig };
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,9 @@ function getDefaultConfig() {
|
|
|
74
74
|
files: ["README.md"],
|
|
75
75
|
dirs: ["docs/"],
|
|
76
76
|
generateAgentFiles: true
|
|
77
|
+
},
|
|
78
|
+
lima: {
|
|
79
|
+
installGh: true
|
|
77
80
|
}
|
|
78
81
|
};
|
|
79
82
|
}
|
|
@@ -97,6 +100,10 @@ function mergeWithDefaults(config) {
|
|
|
97
100
|
context: {
|
|
98
101
|
...defaults.context,
|
|
99
102
|
...config.context
|
|
103
|
+
},
|
|
104
|
+
lima: {
|
|
105
|
+
...defaults.lima,
|
|
106
|
+
...config.lima
|
|
100
107
|
}
|
|
101
108
|
};
|
|
102
109
|
}
|
|
@@ -1003,7 +1010,10 @@ function buildAgentArgs(agent, options) {
|
|
|
1003
1010
|
if (options?.compactPrompt) {
|
|
1004
1011
|
instructionOptions.compact = true;
|
|
1005
1012
|
}
|
|
1006
|
-
|
|
1013
|
+
let promptContent = options?.customPrompt ?? getStandardAgentInstructions(instructionOptions);
|
|
1014
|
+
if (options?.contextContent) {
|
|
1015
|
+
promptContent = promptContent + "\n\n" + options.contextContent;
|
|
1016
|
+
}
|
|
1007
1017
|
const pattern = agent.systemPromptArg;
|
|
1008
1018
|
if (pattern.includes("{prompt}")) {
|
|
1009
1019
|
const parts = pattern.split(/\s+/);
|
|
@@ -1675,7 +1685,24 @@ function getSecretReferences(templateNames) {
|
|
|
1675
1685
|
return refs;
|
|
1676
1686
|
}
|
|
1677
1687
|
|
|
1688
|
+
// src/format.ts
|
|
1689
|
+
import prettier from "prettier";
|
|
1690
|
+
async function formatJson(data) {
|
|
1691
|
+
const json = JSON.stringify(data);
|
|
1692
|
+
return prettier.format(json, {
|
|
1693
|
+
parser: "json",
|
|
1694
|
+
printWidth: 80,
|
|
1695
|
+
tabWidth: 2
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
function formatJsonSync(data) {
|
|
1699
|
+
return JSON.stringify(data, null, 2) + "\n";
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1678
1702
|
// src/mcp.ts
|
|
1703
|
+
function isRemoteType(type) {
|
|
1704
|
+
return type === "remote" || type === "streamable-http";
|
|
1705
|
+
}
|
|
1679
1706
|
function getMcpServers(config) {
|
|
1680
1707
|
const servers = [];
|
|
1681
1708
|
if (!config.mcp?.servers) {
|
|
@@ -1687,10 +1714,12 @@ function getMcpServers(config) {
|
|
|
1687
1714
|
}
|
|
1688
1715
|
const def = serverConfig;
|
|
1689
1716
|
const template = getMcpTemplate(name);
|
|
1717
|
+
const rawType = def.type ?? template?.type ?? "stdio";
|
|
1718
|
+
const displayType = isRemoteType(rawType) ? "remote" : "stdio";
|
|
1690
1719
|
servers.push({
|
|
1691
1720
|
name,
|
|
1692
1721
|
enabled: def.enabled !== false,
|
|
1693
|
-
type:
|
|
1722
|
+
type: displayType,
|
|
1694
1723
|
url: def.url ?? template?.url,
|
|
1695
1724
|
command: def.command ?? template?.command,
|
|
1696
1725
|
template: template ? name : void 0
|
|
@@ -1812,7 +1841,7 @@ function generateMcpConfig(config) {
|
|
|
1812
1841
|
const template = getMcpTemplate(name);
|
|
1813
1842
|
const entry = {};
|
|
1814
1843
|
const type = def.type ?? template?.type ?? "stdio";
|
|
1815
|
-
if (type
|
|
1844
|
+
if (isRemoteType(type)) {
|
|
1816
1845
|
entry.type = "http";
|
|
1817
1846
|
entry.url = def.url ?? template?.url;
|
|
1818
1847
|
entry.headers = def.headers ?? template?.headers;
|
|
@@ -1850,10 +1879,11 @@ function generateOpenCodeConfig(config) {
|
|
|
1850
1879
|
}
|
|
1851
1880
|
const template = getMcpTemplate(name);
|
|
1852
1881
|
const type = def.type ?? template?.type ?? "stdio";
|
|
1882
|
+
const openCodeType = isRemoteType(type) ? "remote" : "local";
|
|
1853
1883
|
const entry = {
|
|
1854
|
-
type
|
|
1884
|
+
type: openCodeType
|
|
1855
1885
|
};
|
|
1856
|
-
if (type
|
|
1886
|
+
if (isRemoteType(type)) {
|
|
1857
1887
|
entry.url = def.url ?? template?.url;
|
|
1858
1888
|
const headers = def.headers ?? template?.headers;
|
|
1859
1889
|
if (headers) {
|
|
@@ -1878,12 +1908,12 @@ async function writeMcpConfig(rootDir, config) {
|
|
|
1878
1908
|
const mcpConfig = generateMcpConfig(config);
|
|
1879
1909
|
const configFile = config.mcp?.configFile ?? ".mcp.json";
|
|
1880
1910
|
const configPath = isAbsolute(configFile) ? configFile : join4(rootDir, configFile);
|
|
1881
|
-
await writeFile2(configPath,
|
|
1911
|
+
await writeFile2(configPath, await formatJson(mcpConfig), "utf-8");
|
|
1882
1912
|
}
|
|
1883
1913
|
async function writeOpenCodeConfig(rootDir, config) {
|
|
1884
1914
|
const openCodeConfig = generateOpenCodeConfig(config);
|
|
1885
1915
|
const configPath = join4(rootDir, "opencode.json");
|
|
1886
|
-
await writeFile2(configPath,
|
|
1916
|
+
await writeFile2(configPath, await formatJson(openCodeConfig), "utf-8");
|
|
1887
1917
|
}
|
|
1888
1918
|
async function hasMcpConfig(rootDir, config) {
|
|
1889
1919
|
const configFile = config?.mcp?.configFile ?? ".mcp.json";
|
|
@@ -1909,6 +1939,286 @@ function getMcpConfigPath(rootDir, config) {
|
|
|
1909
1939
|
const configFile = config?.mcp?.configFile ?? ".mcp.json";
|
|
1910
1940
|
return isAbsolute(configFile) ? configFile : join4(rootDir, configFile);
|
|
1911
1941
|
}
|
|
1942
|
+
|
|
1943
|
+
// src/context.ts
|
|
1944
|
+
import { readFile as readFile6, readdir, access as access4, stat } from "fs/promises";
|
|
1945
|
+
import { join as join5, relative, extname } from "path";
|
|
1946
|
+
import { minimatch } from "minimatch";
|
|
1947
|
+
var DEFAULT_MAX_FILE_SIZE = 100 * 1024;
|
|
1948
|
+
var DEFAULT_MAX_TOTAL_SIZE = 500 * 1024;
|
|
1949
|
+
var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
1950
|
+
// Images
|
|
1951
|
+
".png",
|
|
1952
|
+
".jpg",
|
|
1953
|
+
".jpeg",
|
|
1954
|
+
".gif",
|
|
1955
|
+
".bmp",
|
|
1956
|
+
".ico",
|
|
1957
|
+
".webp",
|
|
1958
|
+
".svg",
|
|
1959
|
+
".tiff",
|
|
1960
|
+
".tif",
|
|
1961
|
+
// Documents
|
|
1962
|
+
".pdf",
|
|
1963
|
+
".doc",
|
|
1964
|
+
".docx",
|
|
1965
|
+
".xls",
|
|
1966
|
+
".xlsx",
|
|
1967
|
+
".ppt",
|
|
1968
|
+
".pptx",
|
|
1969
|
+
".odt",
|
|
1970
|
+
".ods",
|
|
1971
|
+
".odp",
|
|
1972
|
+
// Archives
|
|
1973
|
+
".zip",
|
|
1974
|
+
".tar",
|
|
1975
|
+
".gz",
|
|
1976
|
+
".bz2",
|
|
1977
|
+
".7z",
|
|
1978
|
+
".rar",
|
|
1979
|
+
".xz",
|
|
1980
|
+
// Executables
|
|
1981
|
+
".exe",
|
|
1982
|
+
".dll",
|
|
1983
|
+
".so",
|
|
1984
|
+
".dylib",
|
|
1985
|
+
".bin",
|
|
1986
|
+
".app",
|
|
1987
|
+
// Fonts
|
|
1988
|
+
".woff",
|
|
1989
|
+
".woff2",
|
|
1990
|
+
".ttf",
|
|
1991
|
+
".eot",
|
|
1992
|
+
".otf",
|
|
1993
|
+
// Media
|
|
1994
|
+
".mp3",
|
|
1995
|
+
".mp4",
|
|
1996
|
+
".wav",
|
|
1997
|
+
".avi",
|
|
1998
|
+
".mov",
|
|
1999
|
+
".mkv",
|
|
2000
|
+
".webm",
|
|
2001
|
+
".ogg",
|
|
2002
|
+
".flac",
|
|
2003
|
+
// Data
|
|
2004
|
+
".db",
|
|
2005
|
+
".sqlite",
|
|
2006
|
+
".sqlite3",
|
|
2007
|
+
// Compiled
|
|
2008
|
+
".wasm",
|
|
2009
|
+
".pyc",
|
|
2010
|
+
".pyo",
|
|
2011
|
+
".class",
|
|
2012
|
+
".o",
|
|
2013
|
+
".obj",
|
|
2014
|
+
// Lock files (often binary-ish)
|
|
2015
|
+
".lock",
|
|
2016
|
+
// Package manager
|
|
2017
|
+
"package-lock.json",
|
|
2018
|
+
"pnpm-lock.yaml",
|
|
2019
|
+
"yarn.lock"
|
|
2020
|
+
]);
|
|
2021
|
+
function matchesExcludePattern(relativePath, excludePatterns) {
|
|
2022
|
+
for (const pattern of excludePatterns) {
|
|
2023
|
+
if (minimatch(relativePath, pattern, { dot: true })) {
|
|
2024
|
+
return true;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
return false;
|
|
2028
|
+
}
|
|
2029
|
+
function isBinaryFile(filepath, additionalExtensions) {
|
|
2030
|
+
const ext = extname(filepath).toLowerCase();
|
|
2031
|
+
const filename = filepath.split("/").pop() ?? "";
|
|
2032
|
+
if (BINARY_EXTENSIONS.has(ext)) {
|
|
2033
|
+
return true;
|
|
2034
|
+
}
|
|
2035
|
+
if (BINARY_EXTENSIONS.has(filename)) {
|
|
2036
|
+
return true;
|
|
2037
|
+
}
|
|
2038
|
+
if (additionalExtensions) {
|
|
2039
|
+
for (const addExt of additionalExtensions) {
|
|
2040
|
+
if (ext === addExt || filename === addExt) {
|
|
2041
|
+
return true;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
return false;
|
|
2046
|
+
}
|
|
2047
|
+
async function readContextFile(filepath, rootDir, options = {}) {
|
|
2048
|
+
const maxFileSize = options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
2049
|
+
const absolutePath = filepath.startsWith("/") ? filepath : join5(rootDir, filepath);
|
|
2050
|
+
const relativePath = relative(rootDir, absolutePath);
|
|
2051
|
+
try {
|
|
2052
|
+
await access4(absolutePath);
|
|
2053
|
+
const stats = await stat(absolutePath);
|
|
2054
|
+
if (stats.isDirectory()) {
|
|
2055
|
+
return { path: absolutePath, reason: "directory" };
|
|
2056
|
+
}
|
|
2057
|
+
if (stats.size > maxFileSize) {
|
|
2058
|
+
logger.debug(
|
|
2059
|
+
`Skipping ${relativePath}: exceeds max file size (${stats.size} > ${maxFileSize})`
|
|
2060
|
+
);
|
|
2061
|
+
return { path: absolutePath, reason: "too-large" };
|
|
2062
|
+
}
|
|
2063
|
+
if (isBinaryFile(absolutePath, options.binaryExtensions)) {
|
|
2064
|
+
logger.debug(`Skipping ${relativePath}: binary file extension`);
|
|
2065
|
+
return { path: absolutePath, reason: "binary" };
|
|
2066
|
+
}
|
|
2067
|
+
const content = await readFile6(absolutePath, "utf-8");
|
|
2068
|
+
if (content.includes("\0")) {
|
|
2069
|
+
logger.debug(`Skipping ${relativePath}: contains null bytes`);
|
|
2070
|
+
return { path: absolutePath, reason: "binary" };
|
|
2071
|
+
}
|
|
2072
|
+
return {
|
|
2073
|
+
path: absolutePath,
|
|
2074
|
+
relativePath,
|
|
2075
|
+
content,
|
|
2076
|
+
size: stats.size,
|
|
2077
|
+
truncated: false
|
|
2078
|
+
};
|
|
2079
|
+
} catch (error) {
|
|
2080
|
+
if (error.code === "ENOENT") {
|
|
2081
|
+
logger.debug(`Skipping ${relativePath}: file not found`);
|
|
2082
|
+
return { path: absolutePath, reason: "missing" };
|
|
2083
|
+
}
|
|
2084
|
+
logger.debug(
|
|
2085
|
+
`Skipping ${relativePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
2086
|
+
);
|
|
2087
|
+
return {
|
|
2088
|
+
path: absolutePath,
|
|
2089
|
+
reason: "error",
|
|
2090
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
async function readContextDirectory(dirPath, rootDir, excludePatterns, options = {}) {
|
|
2095
|
+
const files = [];
|
|
2096
|
+
const skipped = [];
|
|
2097
|
+
const absolutePath = dirPath.startsWith("/") ? dirPath : join5(rootDir, dirPath);
|
|
2098
|
+
try {
|
|
2099
|
+
await access4(absolutePath);
|
|
2100
|
+
const stats = await stat(absolutePath);
|
|
2101
|
+
if (!stats.isDirectory()) {
|
|
2102
|
+
const result = await readContextFile(absolutePath, rootDir, options);
|
|
2103
|
+
if ("content" in result) {
|
|
2104
|
+
files.push(result);
|
|
2105
|
+
} else {
|
|
2106
|
+
skipped.push(result);
|
|
2107
|
+
}
|
|
2108
|
+
return { files, skipped };
|
|
2109
|
+
}
|
|
2110
|
+
const entries = await readdir(absolutePath, { withFileTypes: true });
|
|
2111
|
+
for (const entry of entries) {
|
|
2112
|
+
const entryPath = join5(absolutePath, entry.name);
|
|
2113
|
+
const relativePath = relative(rootDir, entryPath);
|
|
2114
|
+
if (matchesExcludePattern(relativePath, excludePatterns)) {
|
|
2115
|
+
skipped.push({ path: entryPath, reason: "excluded" });
|
|
2116
|
+
continue;
|
|
2117
|
+
}
|
|
2118
|
+
if (entry.isDirectory()) {
|
|
2119
|
+
const subResult = await readContextDirectory(entryPath, rootDir, excludePatterns, options);
|
|
2120
|
+
files.push(...subResult.files);
|
|
2121
|
+
skipped.push(...subResult.skipped);
|
|
2122
|
+
} else if (entry.isFile()) {
|
|
2123
|
+
const result = await readContextFile(entryPath, rootDir, options);
|
|
2124
|
+
if ("content" in result) {
|
|
2125
|
+
files.push(result);
|
|
2126
|
+
} else {
|
|
2127
|
+
skipped.push(result);
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
} catch (error) {
|
|
2132
|
+
if (error.code === "ENOENT") {
|
|
2133
|
+
logger.debug(`Directory not found: ${absolutePath}`);
|
|
2134
|
+
} else {
|
|
2135
|
+
logger.debug(
|
|
2136
|
+
`Error reading directory ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
return { files, skipped };
|
|
2141
|
+
}
|
|
2142
|
+
async function assembleContext(rootDir, config, options = {}) {
|
|
2143
|
+
const maxTotalSize = options.maxTotalSize ?? DEFAULT_MAX_TOTAL_SIZE;
|
|
2144
|
+
const excludePatterns = config.exclude ?? [];
|
|
2145
|
+
const allFiles = [];
|
|
2146
|
+
const skippedFiles = [];
|
|
2147
|
+
let totalSize = 0;
|
|
2148
|
+
if (config.files && config.files.length > 0) {
|
|
2149
|
+
for (const filePath of config.files) {
|
|
2150
|
+
const relativePath = filePath;
|
|
2151
|
+
if (matchesExcludePattern(relativePath, excludePatterns)) {
|
|
2152
|
+
skippedFiles.push({ path: filePath, reason: "excluded" });
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
const result = await readContextFile(filePath, rootDir, options);
|
|
2156
|
+
if ("content" in result) {
|
|
2157
|
+
if (totalSize + result.size > maxTotalSize) {
|
|
2158
|
+
logger.debug(`Skipping ${filePath}: would exceed total size limit`);
|
|
2159
|
+
skippedFiles.push({ path: filePath, reason: "too-large" });
|
|
2160
|
+
continue;
|
|
2161
|
+
}
|
|
2162
|
+
totalSize += result.size;
|
|
2163
|
+
allFiles.push(result);
|
|
2164
|
+
} else {
|
|
2165
|
+
skippedFiles.push(result);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
if (config.dirs && config.dirs.length > 0) {
|
|
2170
|
+
for (const dirPath of config.dirs) {
|
|
2171
|
+
const { files, skipped } = await readContextDirectory(
|
|
2172
|
+
dirPath,
|
|
2173
|
+
rootDir,
|
|
2174
|
+
excludePatterns,
|
|
2175
|
+
options
|
|
2176
|
+
);
|
|
2177
|
+
for (const file of files) {
|
|
2178
|
+
if (totalSize + file.size > maxTotalSize) {
|
|
2179
|
+
logger.debug(`Skipping ${file.relativePath}: would exceed total size limit`);
|
|
2180
|
+
skippedFiles.push({ path: file.path, reason: "too-large" });
|
|
2181
|
+
continue;
|
|
2182
|
+
}
|
|
2183
|
+
totalSize += file.size;
|
|
2184
|
+
allFiles.push(file);
|
|
2185
|
+
}
|
|
2186
|
+
skippedFiles.push(...skipped);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
const content = formatContextContent(allFiles, options);
|
|
2190
|
+
return {
|
|
2191
|
+
files: allFiles,
|
|
2192
|
+
totalSize,
|
|
2193
|
+
skippedFiles,
|
|
2194
|
+
content
|
|
2195
|
+
};
|
|
2196
|
+
}
|
|
2197
|
+
function formatContextContent(files, options = {}) {
|
|
2198
|
+
const includeHeaders = options.includeHeaders ?? true;
|
|
2199
|
+
if (files.length === 0) {
|
|
2200
|
+
return "";
|
|
2201
|
+
}
|
|
2202
|
+
const sections = [
|
|
2203
|
+
"## Project Context Files",
|
|
2204
|
+
"",
|
|
2205
|
+
"The following files provide additional context about the project:",
|
|
2206
|
+
""
|
|
2207
|
+
];
|
|
2208
|
+
for (const file of files) {
|
|
2209
|
+
if (includeHeaders) {
|
|
2210
|
+
sections.push(`### ${file.relativePath}`);
|
|
2211
|
+
sections.push("```");
|
|
2212
|
+
sections.push(file.content.trim());
|
|
2213
|
+
sections.push("```");
|
|
2214
|
+
sections.push("");
|
|
2215
|
+
} else {
|
|
2216
|
+
sections.push(file.content.trim());
|
|
2217
|
+
sections.push("");
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
return sections.join("\n");
|
|
2221
|
+
}
|
|
1912
2222
|
export {
|
|
1913
2223
|
CODE_EDITING_GUIDELINES,
|
|
1914
2224
|
COMMUNICATION_GUIDELINES,
|
|
@@ -1923,6 +2233,7 @@ export {
|
|
|
1923
2233
|
addMcpServerFromTemplate,
|
|
1924
2234
|
agentReadsInstructionFiles,
|
|
1925
2235
|
agentSupportsRuntimeInjection,
|
|
2236
|
+
assembleContext,
|
|
1926
2237
|
buildAgentArgs,
|
|
1927
2238
|
checkAgentAvailable,
|
|
1928
2239
|
checkAllAgents,
|
|
@@ -1936,6 +2247,9 @@ export {
|
|
|
1936
2247
|
enableMcpServer,
|
|
1937
2248
|
execInContainer,
|
|
1938
2249
|
formatAuthStatus,
|
|
2250
|
+
formatContextContent,
|
|
2251
|
+
formatJson,
|
|
2252
|
+
formatJsonSync,
|
|
1939
2253
|
generateEnvrc,
|
|
1940
2254
|
generateFullSystemPrompt,
|
|
1941
2255
|
generateMcpConfig,
|
|
@@ -1969,6 +2283,7 @@ export {
|
|
|
1969
2283
|
hasOpCli,
|
|
1970
2284
|
hasOpServiceAccountToken,
|
|
1971
2285
|
hasVaultCli,
|
|
2286
|
+
isBinaryFile,
|
|
1972
2287
|
isOpAuthenticated,
|
|
1973
2288
|
isVaultAuthenticated,
|
|
1974
2289
|
launchAgent,
|
|
@@ -1977,7 +2292,10 @@ export {
|
|
|
1977
2292
|
loadDevcontainerConfig,
|
|
1978
2293
|
loadSecrets,
|
|
1979
2294
|
logger,
|
|
2295
|
+
matchesExcludePattern,
|
|
1980
2296
|
mergeWithDefaults,
|
|
2297
|
+
readContextDirectory,
|
|
2298
|
+
readContextFile,
|
|
1981
2299
|
readEnvrc,
|
|
1982
2300
|
readMcpConfig,
|
|
1983
2301
|
readOpSecret,
|