@wundam/orchex 1.0.0-rc.1
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/LICENSE +65 -0
- package/README.md +332 -0
- package/bin/orchex.js +2 -0
- package/dist/artifacts.d.ts +132 -0
- package/dist/artifacts.js +832 -0
- package/dist/claude-executor.d.ts +31 -0
- package/dist/claude-executor.js +200 -0
- package/dist/commands.d.ts +36 -0
- package/dist/commands.js +264 -0
- package/dist/config.d.ts +100 -0
- package/dist/config.js +172 -0
- package/dist/context-builder.d.ts +46 -0
- package/dist/context-builder.js +506 -0
- package/dist/cost.d.ts +29 -0
- package/dist/cost.js +60 -0
- package/dist/execution-broadcaster.d.ts +18 -0
- package/dist/execution-broadcaster.js +17 -0
- package/dist/executors/base.d.ts +99 -0
- package/dist/executors/base.js +206 -0
- package/dist/executors/circuit-breaker.d.ts +36 -0
- package/dist/executors/circuit-breaker.js +109 -0
- package/dist/executors/deepseek-executor.d.ts +22 -0
- package/dist/executors/deepseek-executor.js +145 -0
- package/dist/executors/gemini-executor.d.ts +20 -0
- package/dist/executors/gemini-executor.js +176 -0
- package/dist/executors/index.d.ts +81 -0
- package/dist/executors/index.js +193 -0
- package/dist/executors/ollama-executor.d.ts +25 -0
- package/dist/executors/ollama-executor.js +184 -0
- package/dist/executors/openai-executor.d.ts +22 -0
- package/dist/executors/openai-executor.js +142 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +115 -0
- package/dist/intelligence/anti-pattern-detector.d.ts +117 -0
- package/dist/intelligence/anti-pattern-detector.js +327 -0
- package/dist/intelligence/budget-enforcer.d.ts +119 -0
- package/dist/intelligence/budget-enforcer.js +226 -0
- package/dist/intelligence/context-optimizer.d.ts +111 -0
- package/dist/intelligence/context-optimizer.js +282 -0
- package/dist/intelligence/cost-tracker.d.ts +114 -0
- package/dist/intelligence/cost-tracker.js +183 -0
- package/dist/intelligence/deliverable-extractor.d.ts +134 -0
- package/dist/intelligence/deliverable-extractor.js +909 -0
- package/dist/intelligence/dependency-inferrer.d.ts +87 -0
- package/dist/intelligence/dependency-inferrer.js +403 -0
- package/dist/intelligence/diagnostics.d.ts +25 -0
- package/dist/intelligence/diagnostics.js +36 -0
- package/dist/intelligence/error-analyzer.d.ts +7 -0
- package/dist/intelligence/error-analyzer.js +76 -0
- package/dist/intelligence/file-chunker.d.ts +15 -0
- package/dist/intelligence/file-chunker.js +64 -0
- package/dist/intelligence/fix-stream-manager.d.ts +59 -0
- package/dist/intelligence/fix-stream-manager.js +212 -0
- package/dist/intelligence/heuristics.d.ts +23 -0
- package/dist/intelligence/heuristics.js +124 -0
- package/dist/intelligence/learning-engine.d.ts +157 -0
- package/dist/intelligence/learning-engine.js +433 -0
- package/dist/intelligence/learning-feedback.d.ts +96 -0
- package/dist/intelligence/learning-feedback.js +202 -0
- package/dist/intelligence/pattern-analyzer.d.ts +35 -0
- package/dist/intelligence/pattern-analyzer.js +189 -0
- package/dist/intelligence/plan-parser.d.ts +124 -0
- package/dist/intelligence/plan-parser.js +498 -0
- package/dist/intelligence/planner.d.ts +29 -0
- package/dist/intelligence/planner.js +86 -0
- package/dist/intelligence/self-healer.d.ts +16 -0
- package/dist/intelligence/self-healer.js +84 -0
- package/dist/intelligence/slicing-metrics.d.ts +62 -0
- package/dist/intelligence/slicing-metrics.js +202 -0
- package/dist/intelligence/slicing-templates.d.ts +81 -0
- package/dist/intelligence/slicing-templates.js +420 -0
- package/dist/intelligence/split-suggester.d.ts +69 -0
- package/dist/intelligence/split-suggester.js +176 -0
- package/dist/intelligence/stream-generator.d.ts +90 -0
- package/dist/intelligence/stream-generator.js +452 -0
- package/dist/logger.d.ts +34 -0
- package/dist/logger.js +83 -0
- package/dist/logging.d.ts +5 -0
- package/dist/logging.js +38 -0
- package/dist/manifest.d.ts +56 -0
- package/dist/manifest.js +254 -0
- package/dist/metrics.d.ts +35 -0
- package/dist/metrics.js +75 -0
- package/dist/orchestrator.d.ts +35 -0
- package/dist/orchestrator.js +723 -0
- package/dist/ownership.d.ts +44 -0
- package/dist/ownership.js +250 -0
- package/dist/semaphore.d.ts +12 -0
- package/dist/semaphore.js +34 -0
- package/dist/telemetry/telemetry-types.d.ts +85 -0
- package/dist/telemetry/telemetry-types.js +1 -0
- package/dist/tier-gating.d.ts +24 -0
- package/dist/tier-gating.js +88 -0
- package/dist/tiers.d.ts +92 -0
- package/dist/tiers.js +108 -0
- package/dist/tools.d.ts +18 -0
- package/dist/tools.js +1363 -0
- package/dist/types.d.ts +740 -0
- package/dist/types.js +160 -0
- package/dist/utils/ownership-validator.d.ts +6 -0
- package/dist/utils/ownership-validator.js +21 -0
- package/dist/waves.d.ts +21 -0
- package/dist/waves.js +146 -0
- package/package.json +120 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { TierIdSchema } from './tiers.js';
|
|
6
|
+
// Well-known URLs
|
|
7
|
+
export const PRODUCTION_URL = 'https://api.orchex.dev';
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// LLM Provider Configuration
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const LLMProviderSchema = z.enum(['anthropic', 'openai', 'gemini', 'ollama', 'deepseek']);
|
|
12
|
+
/**
|
|
13
|
+
* Detect the LLM provider based on available environment variables.
|
|
14
|
+
* Priority: ORCHEX_PROVIDER env var > first available API key
|
|
15
|
+
*/
|
|
16
|
+
export function detectProvider() {
|
|
17
|
+
// Explicit provider override
|
|
18
|
+
const explicit = process.env.ORCHEX_PROVIDER?.toLowerCase();
|
|
19
|
+
if (explicit && ['anthropic', 'openai', 'gemini', 'ollama', 'deepseek'].includes(explicit)) {
|
|
20
|
+
return explicit;
|
|
21
|
+
}
|
|
22
|
+
// Auto-detect from available API keys (priority order)
|
|
23
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
24
|
+
return 'anthropic';
|
|
25
|
+
if (process.env.OPENAI_API_KEY)
|
|
26
|
+
return 'openai';
|
|
27
|
+
if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY)
|
|
28
|
+
return 'gemini';
|
|
29
|
+
if (process.env.DEEPSEEK_API_KEY)
|
|
30
|
+
return 'deepseek';
|
|
31
|
+
if (process.env.OLLAMA_BASE_URL || process.env.OLLAMA_HOST)
|
|
32
|
+
return 'ollama';
|
|
33
|
+
// Default to Anthropic (original behavior)
|
|
34
|
+
return 'anthropic';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the API key for a specific provider from environment variables.
|
|
38
|
+
*/
|
|
39
|
+
export function getProviderApiKey(provider) {
|
|
40
|
+
switch (provider) {
|
|
41
|
+
case 'anthropic':
|
|
42
|
+
return process.env.ANTHROPIC_API_KEY;
|
|
43
|
+
case 'openai':
|
|
44
|
+
return process.env.OPENAI_API_KEY;
|
|
45
|
+
case 'gemini':
|
|
46
|
+
return process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
|
|
47
|
+
case 'deepseek':
|
|
48
|
+
return process.env.DEEPSEEK_API_KEY;
|
|
49
|
+
case 'ollama':
|
|
50
|
+
return undefined; // Ollama doesn't require an API key
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the base URL for a provider (relevant for Ollama).
|
|
55
|
+
*/
|
|
56
|
+
export function getProviderBaseUrl(provider) {
|
|
57
|
+
switch (provider) {
|
|
58
|
+
case 'deepseek':
|
|
59
|
+
return process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com/v1';
|
|
60
|
+
case 'ollama':
|
|
61
|
+
return process.env.OLLAMA_BASE_URL || process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
62
|
+
default:
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Default models for each provider.
|
|
68
|
+
* Used when no model is specified in config or request.
|
|
69
|
+
*/
|
|
70
|
+
export const DEFAULT_MODELS = {
|
|
71
|
+
anthropic: 'claude-sonnet-4-5-20250929',
|
|
72
|
+
openai: 'gpt-4.1',
|
|
73
|
+
gemini: 'gemini-2.0-flash',
|
|
74
|
+
deepseek: 'deepseek-coder',
|
|
75
|
+
ollama: 'llama3.3:70b',
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Get the configured provider.
|
|
79
|
+
* Priority: ORCHEX_PROVIDER env > config file > auto-detect from API keys > default
|
|
80
|
+
*/
|
|
81
|
+
export function getConfiguredProvider(config) {
|
|
82
|
+
// 1. Env var (highest — standard Unix convention)
|
|
83
|
+
const explicit = process.env.ORCHEX_PROVIDER?.toLowerCase();
|
|
84
|
+
if (explicit && LLMProviderSchema.safeParse(explicit).success) {
|
|
85
|
+
return explicit;
|
|
86
|
+
}
|
|
87
|
+
// 2. Config file
|
|
88
|
+
if (config.provider) {
|
|
89
|
+
return config.provider;
|
|
90
|
+
}
|
|
91
|
+
// 3. Auto-detect from API keys / default
|
|
92
|
+
return detectProvider();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the configured model, falling back to provider default.
|
|
96
|
+
* Priority: ORCHEX_MODEL env > config.model > provider default
|
|
97
|
+
*/
|
|
98
|
+
export function getConfiguredModel(config) {
|
|
99
|
+
// 1. Env var (highest — standard Unix convention)
|
|
100
|
+
if (process.env.ORCHEX_MODEL) {
|
|
101
|
+
return process.env.ORCHEX_MODEL;
|
|
102
|
+
}
|
|
103
|
+
// 2. Config file
|
|
104
|
+
if (config.model) {
|
|
105
|
+
return config.model;
|
|
106
|
+
}
|
|
107
|
+
// 3. Fall back to provider default
|
|
108
|
+
const provider = getConfiguredProvider(config);
|
|
109
|
+
return DEFAULT_MODELS[provider];
|
|
110
|
+
}
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Config Schema
|
|
113
|
+
// ============================================================================
|
|
114
|
+
export const TelemetryConfigSchema = z.object({
|
|
115
|
+
enabled: z.boolean().default(false),
|
|
116
|
+
endpoint: z.string().url().optional(), // For future remote telemetry
|
|
117
|
+
});
|
|
118
|
+
export const ConfigSchema = z.object({
|
|
119
|
+
mode: z.enum(['local', 'cloud']).default('local'),
|
|
120
|
+
apiUrl: z.string().url().default(PRODUCTION_URL),
|
|
121
|
+
apiKey: z.string().optional(),
|
|
122
|
+
/** User's subscription tier (synced from cloud on login) */
|
|
123
|
+
tier: TierIdSchema.default('free'),
|
|
124
|
+
/** LLM provider (auto-detected if not set) */
|
|
125
|
+
provider: LLMProviderSchema.optional(),
|
|
126
|
+
/** LLM model (uses provider default if not set) */
|
|
127
|
+
model: z.string().optional(),
|
|
128
|
+
telemetry: TelemetryConfigSchema.default({ enabled: false }),
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* Validate that cloud config has required fields.
|
|
132
|
+
* Returns error message if invalid, undefined if valid.
|
|
133
|
+
*/
|
|
134
|
+
export function validateCloudConfig(config) {
|
|
135
|
+
if (config.mode === 'cloud' && !config.apiKey) {
|
|
136
|
+
return 'Cloud mode requires apiKey. Configure with: orchex config --staging --api-key <your-key>';
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
function configDir() {
|
|
141
|
+
return process.env.ORCHEX_CONFIG_DIR ?? path.join(os.homedir(), '.orchex');
|
|
142
|
+
}
|
|
143
|
+
function configPath() {
|
|
144
|
+
return path.join(configDir(), 'config.json');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Load config from disk. Returns defaults when file doesn't exist.
|
|
148
|
+
*/
|
|
149
|
+
export async function loadConfig() {
|
|
150
|
+
try {
|
|
151
|
+
const raw = await fs.readFile(configPath(), 'utf-8');
|
|
152
|
+
return ConfigSchema.parse(JSON.parse(raw));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (error.code === 'ENOENT') {
|
|
156
|
+
return ConfigSchema.parse({});
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Save partial config. Merges with existing config.
|
|
163
|
+
*/
|
|
164
|
+
export async function saveConfig(partial) {
|
|
165
|
+
const existing = await loadConfig();
|
|
166
|
+
const merged = { ...existing, ...partial };
|
|
167
|
+
const validated = ConfigSchema.parse(merged);
|
|
168
|
+
const dir = configDir();
|
|
169
|
+
await fs.mkdir(dir, { recursive: true });
|
|
170
|
+
await fs.writeFile(configPath(), JSON.stringify(validated, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
171
|
+
return validated;
|
|
172
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Manifest, StructuredPrompt } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build project context: file tree, package.json deps, tsconfig summary.
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildProjectContext(projectDir: string): Promise<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Build stream context: full content of owned and read files.
|
|
8
|
+
* Directory patterns (ending with '/') expand to all files within.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildStreamContext(projectDir: string, owns: string[], reads: string[]): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Build dependency context: summaries and created file contents from completed deps.
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildDependencyContext(projectDir: string, deps: string[], manifest: Manifest): Promise<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Build output instructions: artifact format, rules, constraints.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildInstructions(streamId: string, owns: string[]): string;
|
|
19
|
+
/**
|
|
20
|
+
* Build the complete prompt for an agent, assembling all 4 context layers.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildFullPrompt(projectDir: string, streamId: string, manifest: Manifest): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Options for building an optimized prompt.
|
|
25
|
+
*/
|
|
26
|
+
export interface BuildPromptOptions {
|
|
27
|
+
/** Provider for budget limit lookup (e.g., 'anthropic', 'openai') */
|
|
28
|
+
provider?: string;
|
|
29
|
+
/** Model for more specific limit lookup */
|
|
30
|
+
model?: string;
|
|
31
|
+
/** Whether to enforce hard budget limits (throws ContextBudgetExceededError) */
|
|
32
|
+
enforceHardLimit?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build an optimized prompt with caching hints for cost reduction.
|
|
36
|
+
*
|
|
37
|
+
* Improvements over buildFullPrompt:
|
|
38
|
+
* 1. Uses import graph analysis to prune unused files from context
|
|
39
|
+
* 2. Generates caching hints for Anthropic prompt caching (90% savings on cached content)
|
|
40
|
+
* 3. Returns structured prompt for fine-grained caching control
|
|
41
|
+
* 4. Tracks optimization metrics for telemetry
|
|
42
|
+
* 5. Performs budget validation and includes check results (Orchex Learn)
|
|
43
|
+
*
|
|
44
|
+
* @throws ContextBudgetExceededError if hard limit violated and enforceHardLimit is true
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildFullPromptOptimized(projectDir: string, streamId: string, manifest: Manifest, options?: BuildPromptOptions): Promise<StructuredPrompt>;
|