@xelauvas/xela-cli 0.3.1 → 0.4.0

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 (137) hide show
  1. package/bin/xela.js +0 -12
  2. package/local/README.md +112 -0
  3. package/local/start-qwen.sh +47 -0
  4. package/local/start-tunnel.sh +36 -0
  5. package/local/xela-local.sh +139 -0
  6. package/package.json +9 -5
  7. package/run.sh +33 -0
  8. package/src/Tool.ts +1 -1
  9. package/src/_shims/_generated_stubs/_universal_stub.mjs +168 -0
  10. package/src/_shims/_generated_stubs/stub_346f96741420f62caece15b196e233c6.mjs +19 -0
  11. package/src/_shims/_generated_stubs/stub_4b79af2a6ac1af5a53a55fd666b2bbb4.mjs +3 -0
  12. package/src/_shims/_generated_stubs/stub_94345ddeadacc184ff895597ec5abf71.mjs +6 -0
  13. package/src/_shims/_generated_stubs/stub_99fa0bc272643c549d8a2ec6d578436f.mjs +3 -0
  14. package/src/_shims/_generated_stubs/stub_e3451b131fcaf272a2a75270b9a427a3.mjs +9 -0
  15. package/src/_shims/_generated_stubs/text_stub.mjs +1 -0
  16. package/src/_shims/bun_bundle.js +79 -4
  17. package/src/_shims/cjs_stub.cjs +32 -10
  18. package/src/_shims/loader.js +104 -5
  19. package/src/_shims/openai_adapter.ts +446 -230
  20. package/src/_shims/register.js +16 -3
  21. package/src/assistant/gate.ts +15 -0
  22. package/src/assistant/index.ts +89 -0
  23. package/src/bootstrap/state.ts +6 -1
  24. package/src/bridge/peerSessions.ts +18 -0
  25. package/src/cli/print.ts +5 -0
  26. package/src/commands/assistant/assistant.ts +17 -0
  27. package/src/commands/assistant/index.ts +11 -0
  28. package/src/commands/brief.ts +3 -1
  29. package/src/commands/buddy/buddy.ts +88 -0
  30. package/src/commands/buddy/index.ts +12 -0
  31. package/src/commands/model/model.tsx +8 -23
  32. package/src/commands/peers/index.ts +11 -0
  33. package/src/commands/peers/peers.ts +24 -0
  34. package/src/commands/proactive/proactive.ts +64 -0
  35. package/src/commands/proactive.ts +12 -0
  36. package/src/commands/workflows/index.ts +12 -0
  37. package/src/commands/workflows/workflows.ts +36 -0
  38. package/src/commands.ts +4 -8
  39. package/src/components/Messages.tsx +1 -1
  40. package/src/components/ModelPicker.tsx +4 -34
  41. package/src/components/Spinner.tsx +54 -1
  42. package/src/components/StructuredDiff/colorDiff.ts +3 -1
  43. package/src/components/messages/SnipBoundaryMessage.tsx +15 -0
  44. package/src/components/messages/UserCrossSessionMessage.tsx +26 -0
  45. package/src/components/permissions/PermissionRequest.tsx +4 -2
  46. package/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.tsx +96 -0
  47. package/src/constants/prompts.ts +26 -0
  48. package/src/ink/terminal.ts +9 -1
  49. package/src/jobs/classifier.ts +103 -0
  50. package/src/memdir/paths.ts +13 -1
  51. package/src/proactive/index.ts +158 -0
  52. package/src/proactive/useProactive.ts +78 -0
  53. package/src/screens/REPL.tsx +28 -8
  54. package/src/services/api/claude.ts +6 -1
  55. package/src/services/compact/autoCompact.ts +18 -4
  56. package/src/services/compact/cachedMCConfig.ts +1 -0
  57. package/src/services/compact/cachedMicrocompact.ts +113 -0
  58. package/src/services/compact/compact.ts +22 -2
  59. package/src/services/compact/reactiveCompact.ts +251 -0
  60. package/src/services/compact/snipCompact.ts +282 -0
  61. package/src/services/compact/snipProjection.ts +50 -0
  62. package/src/services/contextCollapse/index.ts +322 -0
  63. package/src/services/contextCollapse/operations.ts +187 -0
  64. package/src/services/contextCollapse/persist.ts +40 -0
  65. package/src/services/extractMemories/extractMemories.ts +11 -2
  66. package/src/services/skillSearch/featureCheck.ts +12 -0
  67. package/src/services/skillSearch/localSearch.ts +98 -0
  68. package/src/services/skillSearch/prefetch.ts +125 -0
  69. package/src/services/skillSearch/remoteSkillLoader.ts +9 -0
  70. package/src/services/skillSearch/remoteSkillState.ts +21 -0
  71. package/src/services/skillSearch/signals.ts +7 -0
  72. package/src/services/skillSearch/telemetry.ts +9 -0
  73. package/src/setup.ts +10 -5
  74. package/src/skills/bundled/dream.ts +31 -0
  75. package/src/skills/bundled/hunter.ts +45 -0
  76. package/src/skills/bundled/index.ts +10 -23
  77. package/src/skills/bundled/runSkillGenerator.ts +61 -0
  78. package/src/skills/mcpSkills.ts +101 -0
  79. package/src/tasks/LocalWorkflowTask/LocalWorkflowTask.ts +301 -0
  80. package/src/tasks/MonitorMcpTask/MonitorMcpTask.ts +273 -0
  81. package/src/tasks.ts +22 -8
  82. package/src/tools/AgentTool/runAgent.ts +11 -0
  83. package/src/tools/BriefTool/BriefTool.ts +2 -0
  84. package/src/tools/CtxInspectTool/CtxInspectTool.ts +102 -0
  85. package/src/tools/DiscoverSkillsTool/DiscoverSkillsTool.ts +78 -0
  86. package/src/tools/DiscoverSkillsTool/prompt.ts +3 -0
  87. package/src/tools/ListPeersTool/ListPeersTool.ts +89 -0
  88. package/src/tools/MCPTool/MCPTool.ts +6 -0
  89. package/src/tools/MonitorTool/MonitorTool.ts +273 -0
  90. package/src/tools/MonitorTool/UI.tsx +25 -0
  91. package/src/tools/MonitorTool/events.ts +84 -0
  92. package/src/tools/MonitorTool/prompt.ts +45 -0
  93. package/src/tools/OverflowTestTool/OverflowTestTool.ts +73 -0
  94. package/src/tools/PushNotificationTool/PushNotificationTool.ts +119 -0
  95. package/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts +93 -0
  96. package/src/tools/ReviewArtifactTool/prompt.ts +5 -0
  97. package/src/tools/SendUserFileTool/SendUserFileTool.ts +87 -0
  98. package/src/tools/SendUserFileTool/prompt.ts +7 -0
  99. package/src/tools/SleepTool/SleepTool.ts +126 -0
  100. package/src/tools/SnipTool/SnipTool.ts +90 -0
  101. package/src/tools/SnipTool/prompt.ts +5 -0
  102. package/src/tools/SubscribePRTool/SubscribePRTool.ts +115 -0
  103. package/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts +129 -0
  104. package/src/tools/TerminalCaptureTool/prompt.ts +8 -0
  105. package/src/tools/ToolSearchTool/prompt.ts +1 -1
  106. package/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts +99 -0
  107. package/src/tools/WebBrowserTool/WebBrowserPanel.tsx +10 -0
  108. package/src/tools/WebBrowserTool/WebBrowserTool.ts +190 -0
  109. package/src/tools/WebBrowserTool/prompt.ts +16 -0
  110. package/src/tools/WorkflowTool/UI.tsx +27 -0
  111. package/src/tools/WorkflowTool/WorkflowTool.ts +401 -0
  112. package/src/tools/WorkflowTool/bundled/index.ts +88 -0
  113. package/src/tools/WorkflowTool/constants.ts +7 -0
  114. package/src/tools/WorkflowTool/createWorkflowCommand.ts +84 -0
  115. package/src/tools/WorkflowTool/prompt.ts +38 -0
  116. package/src/tools/WorkflowTool/runtime.ts +331 -0
  117. package/src/tools.ts +36 -31
  118. package/src/utils/betas.ts +5 -0
  119. package/src/utils/context.ts +9 -0
  120. package/src/utils/conversationRecovery.ts +1 -1
  121. package/src/utils/forkedAgent.ts +4 -0
  122. package/src/utils/logoV2Utils.ts +7 -3
  123. package/src/utils/messageQueueManager.ts +23 -9
  124. package/src/utils/model/model.ts +10 -9
  125. package/src/utils/model/modelOptions.ts +0 -21
  126. package/src/utils/model/validateModel.ts +0 -19
  127. package/src/utils/permissions/permissionSetup.ts +5 -0
  128. package/src/utils/permissions/permissions.ts +25 -0
  129. package/src/utils/permissions/yolo-classifier-prompts/auto_mode_system_prompt.txt +38 -0
  130. package/src/utils/permissions/yolo-classifier-prompts/permissions_external.txt +25 -0
  131. package/src/utils/permissions/yoloClassifier.ts +28 -6
  132. package/src/utils/plugins/officialMarketplaceStartupCheck.ts +9 -0
  133. package/src/utils/systemThemeWatcher.ts +62 -0
  134. package/src/utils/udsClient.ts +115 -0
  135. package/src/utils/udsMessaging.ts +157 -0
  136. package/src/utils/yaml.ts +251 -5
  137. package/src/utils/model/providerModels.ts +0 -168
@@ -1,8 +1,83 @@
1
1
  // Shim for bun:bundle - replaces build-time feature flags with runtime config
2
- // All features default to false (minimal external build)
3
- const ENABLED_FEATURES = new Set([
4
- // Only enable what's absolutely needed for basic REPL
5
- ]);
2
+ // Only client-side features are enabled. Flags that need Anthropic servers
3
+ // (KAIROS, CCR, BRIDGE, DAEMON, telemetry, server-side context management)
4
+ // stay off. Override with XELA_FEATURES="FLAG_A,FLAG_B" (replaces the list)
5
+ // or XELA_FEATURES_DISABLE="FLAG_A" (removes from the list).
6
+ // Flags whose code the fork lacks are stubbed by the loader; the ones that
7
+ // still need Anthropic servers (KAIROS, CCR, DAEMON, telemetry, CACHED_MICROCOMPACT)
8
+ // stay off. TREE_SITTER_BASH needs web-tree-sitter, CACHED_MICROCOMPACT the
9
+ // Anthropic API.
10
+ const DEFAULT_FEATURES = [
11
+ // Permissions: auto mode (⏵⏵ Auto via Shift+Tab) runs the classifier on the configured model
12
+ 'TRANSCRIPT_CLASSIFIER',
13
+ 'BASH_CLASSIFIER',
14
+ // Agents: teams/agents panel, Explore/Plan built-in subagents, fork subagent, verification agent
15
+ 'TEAMMEM',
16
+ 'BUILTIN_EXPLORE_PLAN_AGENTS',
17
+ 'FORK_SUBAGENT',
18
+ 'VERIFICATION_AGENT',
19
+ 'AGENT_MEMORY_SNAPSHOT',
20
+ // Background sessions and the Monitor tool (reimplemented in tools/MonitorTool)
21
+ 'BG_SESSIONS',
22
+ 'MONITOR_TOOL',
23
+ // Workflow scripts (reimplemented in tools/WorkflowTool)
24
+ 'WORKFLOW_SCRIPTS',
25
+ // Context management: snip (model-driven), collapse (background summaries), compact on prompt-too-long
26
+ 'HISTORY_SNIP',
27
+ 'CONTEXT_COLLAPSE',
28
+ 'REACTIVE_COMPACT',
29
+ 'TOKEN_BUDGET',
30
+ 'COMPACTION_REMINDERS',
31
+ // UI
32
+ 'MESSAGE_ACTIONS',
33
+ 'HISTORY_PICKER',
34
+ 'QUICK_SEARCH',
35
+ 'AUTO_THEME',
36
+ 'HOOK_PROMPTS',
37
+ // Tools reimplemented here: terminal panel capture (tmux), headless browser (gstack browse), local skill discovery
38
+ 'TERMINAL_PANEL',
39
+ 'WEB_BROWSER_TOOL',
40
+ 'EXPERIMENTAL_SKILL_SEARCH',
41
+ // Misc
42
+ 'MCP_SKILLS',
43
+ 'NEW_INIT',
44
+ 'ULTRATHINK',
45
+ // Cross-session messaging (SendMessage to uds:<socket>, /peers, ListPeers)
46
+ 'UDS_INBOX',
47
+ // Proactive mode (/proactive, Sleep tool, <tick> check-ins)
48
+ 'PROACTIVE',
49
+ // Skills & tools reimplemented locally
50
+ 'KAIROS_DREAM', // /dream memory consolidation
51
+ 'KAIROS_PUSH_NOTIFICATION', // PushNotification tool (terminal/OS notification)
52
+ 'KAIROS_GITHUB_WEBHOOKS', // SubscribePR tool (gh polling through Monitor)
53
+ 'REVIEW_ARTIFACT', // /hunter + ReviewArtifact tool
54
+ 'RUN_SKILL_GENERATOR', // /run-skill-generator
55
+ 'BUILDING_CLAUDE_APPS', // /claude-api skill
56
+ 'AGENT_TRIGGERS', // CronCreate/CronList/CronDelete + /loop
57
+ 'BUDDY', // /buddy companion
58
+ 'TEMPLATES', // background job state (CLAUDE_JOB_DIR)
59
+ 'AWAY_SUMMARY',
60
+ 'UNATTENDED_RETRY',
61
+ 'DUMP_SYSTEM_PROMPT',
62
+ 'NATIVE_CLIPBOARD_IMAGE',
63
+ 'MCP_RICH_OUTPUT',
64
+ // Assistant mode (xela-local --assistant, CLAUDE_CODE_ASSISTANT=1 or
65
+ // .claude/agents/assistant.md) and brief mode (/brief, SendUserMessage tool)
66
+ 'KAIROS',
67
+ 'KAIROS_BRIEF',
68
+ // Background memory extraction after turns (every 3 turns locally; see
69
+ // memdir/paths.ts isExtractGateOpen)
70
+ 'EXTRACT_MEMORIES',
71
+ ];
72
+
73
+ const ENABLED_FEATURES = new Set(
74
+ process.env.XELA_FEATURES
75
+ ? process.env.XELA_FEATURES.split(',').map(s => s.trim()).filter(Boolean)
76
+ : DEFAULT_FEATURES,
77
+ );
78
+ for (const f of (process.env.XELA_FEATURES_DISABLE || '').split(',')) {
79
+ if (f.trim()) ENABLED_FEATURES.delete(f.trim());
80
+ }
6
81
 
7
82
  export function feature(name) {
8
83
  return ENABLED_FEATURES.has(name);
@@ -1,23 +1,45 @@
1
- // CJS stub for missing/DCE'd modules
2
- // Returns safe defaults for any property access
3
- const noop = () => {};
1
+ // CJS stub for missing/DCE'd modules.
2
+ //
3
+ // Named exports resolve to `undefined`, so feature-gated code written as
4
+ // `feature('X') ? require('./mod.js').Thing : null` degrades to "feature
5
+ // absent" instead of receiving a no-op function that the app then treats as a
6
+ // real tool, task or command (which used to break startup silently).
7
+ // The default export is '' for text-file imports (.txt/.md), and the object is
8
+ // still callable (returns '') for code that invokes the module itself.
9
+ // Stub function by name: predicates stay false, getters/loaders yield nothing,
10
+ // transform-style helpers (project/apply/convert...) pass their input through.
11
+ function stubFunctionFor(name) {
12
+ if (/^(is|has|should|can|was|needs|allow|supports|uses|matches|includes|contains)[A-Z_]/.test(name)) return () => false;
13
+ if (/^(get|find|read|load|fetch|resolve|create|build|make|compute|calculate|extract|lookup|select|detect)[A-Z_]/.test(name)) return () => undefined;
14
+ return (x) => x;
15
+ }
16
+ const noop = (x) => x;
4
17
 
5
- // Make a string-like object that also works as a function
6
- const stub = new Proxy(noop, {
18
+ function makeStub(spec) {
19
+ return new Proxy(noop, {
7
20
  get(target, prop) {
21
+ if (prop === '__makeStub') return makeStub;
8
22
  if (prop === '__esModule') return true;
9
- // .default should return empty string (for text file imports like .txt/.md)
10
23
  if (prop === 'default') return '';
11
24
  if (prop === 'then') return undefined; // Not a Promise
12
25
  if (prop === Symbol.toPrimitive) return () => '';
13
26
  if (prop === Symbol.iterator) return undefined;
14
27
  if (prop === Symbol.asyncIterator) return undefined;
15
- // String methods should work (trimEnd, etc.)
28
+ // String methods keep working for code that treats the module as text
16
29
  if (typeof ''[prop] === 'function') return String.prototype[prop].bind('');
17
- // Return a no-op function for any other property
18
- return noop;
30
+ if (process.env.XELA_LOADER_DEBUG) {
31
+ process.stderr.write(`[require] STUB property ${String(prop)} requested from missing module ${spec}\n`);
32
+ }
33
+ // PascalCase names are classes, tools, tasks, components: `undefined` lets
34
+ // `feature('X') ? require(m).Thing : null` skip them. camelCase names are
35
+ // functions: an inert no-op keeps `isFooEnabled()`-style checks falsy.
36
+ if (typeof prop === 'string' && /^[A-Z]/.test(prop)) return undefined;
37
+ return typeof prop === 'string' ? stubFunctionFor(prop) : noop;
19
38
  },
20
39
  apply() { return ''; },
21
- });
40
+ });
41
+ }
22
42
 
43
+ const stub = makeStub('(unknown)');
23
44
  module.exports = stub;
45
+ module.exports.__makeStub = makeStub;
@@ -231,8 +231,83 @@ try { writeFileSync(UNIVERSAL_STUB_PATH, UNIVERSAL_STUB_SOURCE); } catch {}
231
231
  const UNIVERSAL_STUB_URL = pathToFileURL(UNIVERSAL_STUB_PATH).href;
232
232
  stubUrls.add(UNIVERSAL_STUB_URL);
233
233
 
234
- function generateStubUrl(_specifier) {
235
- return UNIVERSAL_STUB_URL;
234
+ // XELA_LOADER_DEBUG=1 lists every import that resolved to a stub (missing module)
235
+ const LOADER_DEBUG = !!process.env.XELA_LOADER_DEBUG;
236
+
237
+ // Stub value heuristics, by export name:
238
+ // PascalCase (classes, tools, components, tasks) -> undefined, so
239
+ // `feature('X') ? mod.Thing : null` style code skips the feature;
240
+ // UPPER_SNAKE constants -> [] when plural-looking, '' otherwise, so
241
+ // `.length`, spreads and string ops keep working;
242
+ // camelCase functions -> a no-op returning undefined.
243
+ function stubValueFor(name) {
244
+ if (/^[A-Z][A-Z0-9_]*$/.test(name)) {
245
+ return /(S|LIST|TOOLS|KEYS|NAMES|PATHS|TYPES|FLAGS)$/.test(name) ? '[]' : "''";
246
+ }
247
+ if (/^[A-Z]/.test(name)) return 'undefined';
248
+ // predicates stay false, getters/loaders yield nothing, transform-style
249
+ // helpers (projectView(messages), applyX(messages)) pass their input through
250
+ if (/^(is|has|should|can|was|needs|allow|supports|uses|matches|includes|contains)[A-Z_]/.test(name)) return '() => false';
251
+ if (/^(get|find|read|load|fetch|resolve|create|build|make|compute|calculate|extract|lookup|select|detect)[A-Z_]/.test(name)) return '() => undefined';
252
+ return '(x) => x';
253
+ }
254
+
255
+ // Build a stub tailored to what the importing file actually imports from the
256
+ // missing specifier. A universal stub cannot know every export name, and an
257
+ // ESM import of a name the stub lacks is a link-time error.
258
+ function collectImportedNames(parentSource, specifier) {
259
+ const names = new Set();
260
+ let hasDefault = false;
261
+ let hasNamespace = false;
262
+ const esc = specifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
263
+ const re = new RegExp(
264
+ `import\\s+(?:type\\s+)?([^;'"]*?)\\s+from\\s+['"]${esc}['"]|export\\s+(?:type\\s+)?(\\{[^}]*\\})\\s+from\\s+['"]${esc}['"]`,
265
+ 'g',
266
+ );
267
+ let m;
268
+ while ((m = re.exec(parentSource)) !== null) {
269
+ const clause = (m[1] ?? m[2] ?? '').trim();
270
+ if (!clause) continue;
271
+ if (clause.startsWith('*')) { hasNamespace = true; continue; }
272
+ const braces = clause.match(/\{([^}]*)\}/);
273
+ const before = clause.replace(/\{[^}]*\}/, '').replace(/,/g, '').trim();
274
+ if (before && !before.startsWith('type ')) hasDefault = true;
275
+ if (braces) {
276
+ for (const part of braces[1].split(',')) {
277
+ const p = part.trim().replace(/^type\s+/, '');
278
+ if (!p) continue;
279
+ const asMatch = p.match(/^(\S+)\s+as\s+(\S+)$/);
280
+ const exported = asMatch ? asMatch[1] : p;
281
+ if (exported === 'default') { hasDefault = true; continue; }
282
+ names.add(exported);
283
+ }
284
+ }
285
+ }
286
+ return { names: [...names], hasDefault, hasNamespace };
287
+ }
288
+
289
+ function generateStubUrl(specifier, parentURL) {
290
+ const parent = parentURL ? fileURLToPath(parentURL) : null;
291
+ if (LOADER_DEBUG) {
292
+ process.stderr.write(`[loader] STUB ${specifier} <- ${parent ? parent.replace(SRC_ROOT + '/', '') : '?'}\n`);
293
+ }
294
+ if (!parent) return UNIVERSAL_STUB_URL;
295
+ let source = '';
296
+ try { source = readFileSync(parent, 'utf-8'); } catch { return UNIVERSAL_STUB_URL; }
297
+ const { names, hasDefault } = collectImportedNames(source, specifier);
298
+ if (LOADER_DEBUG) process.stderr.write(`[loader] names for ${specifier}: ${names.join(',') || '(none)'} default=${hasDefault}\n`);
299
+ if (names.length === 0 && !hasDefault) return UNIVERSAL_STUB_URL;
300
+ const lines = [`// Generated stub for missing module ${specifier} (imported by ${parent.replace(SRC_ROOT + '/', '')})`];
301
+ for (const name of names) lines.push(`export const ${name} = ${stubValueFor(name)};`);
302
+ lines.push(`export default ${hasDefault ? "''" : '{}'};`);
303
+ const key = createHash('md5').update(specifier + '|' + names.sort().join(',') + '|' + hasDefault).digest('hex');
304
+ const stubPath = join(STUB_DIR, `stub_${key}.mjs`);
305
+ if (!isFile(stubPath)) {
306
+ try { writeFileSync(stubPath, lines.join('\n') + '\n'); } catch { return UNIVERSAL_STUB_URL; }
307
+ }
308
+ const url = pathToFileURL(stubPath).href;
309
+ stubUrls.add(url);
310
+ return url;
236
311
  }
237
312
 
238
313
  export async function resolve(specifier, context, nextResolve) {
@@ -248,7 +323,7 @@ export async function resolve(specifier, context, nextResolve) {
248
323
  if (resolved) {
249
324
  return { url: pathToFileURL(resolved).href, shortCircuit: true };
250
325
  }
251
- const stubUrl = generateStubUrl(specifier);
326
+ const stubUrl = generateStubUrl(specifier, context.parentURL);
252
327
  return { url: stubUrl, shortCircuit: true };
253
328
  }
254
329
 
@@ -269,7 +344,7 @@ export async function resolve(specifier, context, nextResolve) {
269
344
  return { url: pathToFileURL(textStubPath).href, shortCircuit: true };
270
345
  }
271
346
  // Extract the basename for stub generation
272
- const stubUrl = generateStubUrl(specifier.split('/').pop().replace(/\.\w+$/, ''));
347
+ const stubUrl = generateStubUrl(specifier, context.parentURL);
273
348
  return { url: stubUrl, shortCircuit: true };
274
349
  }
275
350
 
@@ -278,7 +353,7 @@ export async function resolve(specifier, context, nextResolve) {
278
353
  const result = await nextResolve(specifier, context);
279
354
  return result;
280
355
  } catch (err) {
281
- const stubUrl = generateStubUrl(specifier.split('/').pop() || specifier);
356
+ const stubUrl = generateStubUrl(specifier, context.parentURL);
282
357
  return { url: stubUrl, shortCircuit: true };
283
358
  }
284
359
  }
@@ -314,6 +389,30 @@ export function load(url, context, nextLoad) {
314
389
  sourcefile: filePath,
315
390
  }));
316
391
 
392
+ // Dynamic import() of a module that does not exist (feature-gated code
393
+ // that was stripped): resolve to a proxy whose camelCase members are
394
+ // pass-through functions and PascalCase members are undefined, instead
395
+ // of a stub that cannot know which names the caller will read.
396
+ code = code.replace(/\bimport\((['"])((?:\.|src\/)[^'"]+)\1\)/g, (full, q, spec) => {
397
+ const base = spec.startsWith('src/') ? join(SRC_ROOT, spec.slice(4)) : pathResolve(dirname(filePath), spec);
398
+ if (tryResolveFile(base)) return full;
399
+ if (LOADER_DEBUG) process.stderr.write(`[loader] DYNAMIC STUB ${spec} <- ${filePath.replace(SRC_ROOT + '/', '')}\n`);
400
+ return `Promise.resolve(globalThis.__xelaMissingModule(${JSON.stringify(spec)}))`;
401
+ });
402
+ if (code.includes('__xelaMissingModule(')) {
403
+ code = `globalThis.__xelaMissingModule ??= (spec) => new Proxy({}, { get(_t, prop) {
404
+ if (prop === 'then') return undefined;
405
+ if (prop === 'default') return '';
406
+ if (typeof prop !== 'string') return undefined;
407
+ if (/^[A-Z][A-Z0-9_]*$/.test(prop)) return /(S|LIST|TOOLS|KEYS|NAMES|PATHS|TYPES|FLAGS)$/.test(prop) ? [] : '';
408
+ if (/^[A-Z]/.test(prop)) return undefined;
409
+ if (/^(is|has|should|can|was|needs|allow|supports|uses|matches|includes|contains)[A-Z_]/.test(prop)) return () => false;
410
+ if (/^(get|find|read|load|fetch|resolve|create|build|make|compute|calculate|extract|lookup|select|detect)[A-Z_]/.test(prop)) return () => undefined;
411
+ return (x) => x;
412
+ } });
413
+ ` + code;
414
+ }
415
+
317
416
  // If the compiled code still has require() calls, inject a CJS-compatible require
318
417
  // that resolves relative to this file's directory
319
418
  if (code.includes('require(') || code.includes('require.resolve(')) {