@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.
Files changed (104) hide show
  1. package/LICENSE +65 -0
  2. package/README.md +332 -0
  3. package/bin/orchex.js +2 -0
  4. package/dist/artifacts.d.ts +132 -0
  5. package/dist/artifacts.js +832 -0
  6. package/dist/claude-executor.d.ts +31 -0
  7. package/dist/claude-executor.js +200 -0
  8. package/dist/commands.d.ts +36 -0
  9. package/dist/commands.js +264 -0
  10. package/dist/config.d.ts +100 -0
  11. package/dist/config.js +172 -0
  12. package/dist/context-builder.d.ts +46 -0
  13. package/dist/context-builder.js +506 -0
  14. package/dist/cost.d.ts +29 -0
  15. package/dist/cost.js +60 -0
  16. package/dist/execution-broadcaster.d.ts +18 -0
  17. package/dist/execution-broadcaster.js +17 -0
  18. package/dist/executors/base.d.ts +99 -0
  19. package/dist/executors/base.js +206 -0
  20. package/dist/executors/circuit-breaker.d.ts +36 -0
  21. package/dist/executors/circuit-breaker.js +109 -0
  22. package/dist/executors/deepseek-executor.d.ts +22 -0
  23. package/dist/executors/deepseek-executor.js +145 -0
  24. package/dist/executors/gemini-executor.d.ts +20 -0
  25. package/dist/executors/gemini-executor.js +176 -0
  26. package/dist/executors/index.d.ts +81 -0
  27. package/dist/executors/index.js +193 -0
  28. package/dist/executors/ollama-executor.d.ts +25 -0
  29. package/dist/executors/ollama-executor.js +184 -0
  30. package/dist/executors/openai-executor.d.ts +22 -0
  31. package/dist/executors/openai-executor.js +142 -0
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.js +115 -0
  34. package/dist/intelligence/anti-pattern-detector.d.ts +117 -0
  35. package/dist/intelligence/anti-pattern-detector.js +327 -0
  36. package/dist/intelligence/budget-enforcer.d.ts +119 -0
  37. package/dist/intelligence/budget-enforcer.js +226 -0
  38. package/dist/intelligence/context-optimizer.d.ts +111 -0
  39. package/dist/intelligence/context-optimizer.js +282 -0
  40. package/dist/intelligence/cost-tracker.d.ts +114 -0
  41. package/dist/intelligence/cost-tracker.js +183 -0
  42. package/dist/intelligence/deliverable-extractor.d.ts +134 -0
  43. package/dist/intelligence/deliverable-extractor.js +909 -0
  44. package/dist/intelligence/dependency-inferrer.d.ts +87 -0
  45. package/dist/intelligence/dependency-inferrer.js +403 -0
  46. package/dist/intelligence/diagnostics.d.ts +25 -0
  47. package/dist/intelligence/diagnostics.js +36 -0
  48. package/dist/intelligence/error-analyzer.d.ts +7 -0
  49. package/dist/intelligence/error-analyzer.js +76 -0
  50. package/dist/intelligence/file-chunker.d.ts +15 -0
  51. package/dist/intelligence/file-chunker.js +64 -0
  52. package/dist/intelligence/fix-stream-manager.d.ts +59 -0
  53. package/dist/intelligence/fix-stream-manager.js +212 -0
  54. package/dist/intelligence/heuristics.d.ts +23 -0
  55. package/dist/intelligence/heuristics.js +124 -0
  56. package/dist/intelligence/learning-engine.d.ts +157 -0
  57. package/dist/intelligence/learning-engine.js +433 -0
  58. package/dist/intelligence/learning-feedback.d.ts +96 -0
  59. package/dist/intelligence/learning-feedback.js +202 -0
  60. package/dist/intelligence/pattern-analyzer.d.ts +35 -0
  61. package/dist/intelligence/pattern-analyzer.js +189 -0
  62. package/dist/intelligence/plan-parser.d.ts +124 -0
  63. package/dist/intelligence/plan-parser.js +498 -0
  64. package/dist/intelligence/planner.d.ts +29 -0
  65. package/dist/intelligence/planner.js +86 -0
  66. package/dist/intelligence/self-healer.d.ts +16 -0
  67. package/dist/intelligence/self-healer.js +84 -0
  68. package/dist/intelligence/slicing-metrics.d.ts +62 -0
  69. package/dist/intelligence/slicing-metrics.js +202 -0
  70. package/dist/intelligence/slicing-templates.d.ts +81 -0
  71. package/dist/intelligence/slicing-templates.js +420 -0
  72. package/dist/intelligence/split-suggester.d.ts +69 -0
  73. package/dist/intelligence/split-suggester.js +176 -0
  74. package/dist/intelligence/stream-generator.d.ts +90 -0
  75. package/dist/intelligence/stream-generator.js +452 -0
  76. package/dist/logger.d.ts +34 -0
  77. package/dist/logger.js +83 -0
  78. package/dist/logging.d.ts +5 -0
  79. package/dist/logging.js +38 -0
  80. package/dist/manifest.d.ts +56 -0
  81. package/dist/manifest.js +254 -0
  82. package/dist/metrics.d.ts +35 -0
  83. package/dist/metrics.js +75 -0
  84. package/dist/orchestrator.d.ts +35 -0
  85. package/dist/orchestrator.js +723 -0
  86. package/dist/ownership.d.ts +44 -0
  87. package/dist/ownership.js +250 -0
  88. package/dist/semaphore.d.ts +12 -0
  89. package/dist/semaphore.js +34 -0
  90. package/dist/telemetry/telemetry-types.d.ts +85 -0
  91. package/dist/telemetry/telemetry-types.js +1 -0
  92. package/dist/tier-gating.d.ts +24 -0
  93. package/dist/tier-gating.js +88 -0
  94. package/dist/tiers.d.ts +92 -0
  95. package/dist/tiers.js +108 -0
  96. package/dist/tools.d.ts +18 -0
  97. package/dist/tools.js +1363 -0
  98. package/dist/types.d.ts +740 -0
  99. package/dist/types.js +160 -0
  100. package/dist/utils/ownership-validator.d.ts +6 -0
  101. package/dist/utils/ownership-validator.js +21 -0
  102. package/dist/waves.d.ts +21 -0
  103. package/dist/waves.js +146 -0
  104. 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>;