@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.
- package/bin/xela.js +0 -12
- package/local/README.md +112 -0
- package/local/start-qwen.sh +47 -0
- package/local/start-tunnel.sh +36 -0
- package/local/xela-local.sh +139 -0
- package/package.json +9 -5
- package/run.sh +33 -0
- package/src/Tool.ts +1 -1
- package/src/_shims/_generated_stubs/_universal_stub.mjs +168 -0
- package/src/_shims/_generated_stubs/stub_346f96741420f62caece15b196e233c6.mjs +19 -0
- package/src/_shims/_generated_stubs/stub_4b79af2a6ac1af5a53a55fd666b2bbb4.mjs +3 -0
- package/src/_shims/_generated_stubs/stub_94345ddeadacc184ff895597ec5abf71.mjs +6 -0
- package/src/_shims/_generated_stubs/stub_99fa0bc272643c549d8a2ec6d578436f.mjs +3 -0
- package/src/_shims/_generated_stubs/stub_e3451b131fcaf272a2a75270b9a427a3.mjs +9 -0
- package/src/_shims/_generated_stubs/text_stub.mjs +1 -0
- package/src/_shims/bun_bundle.js +79 -4
- package/src/_shims/cjs_stub.cjs +32 -10
- package/src/_shims/loader.js +104 -5
- package/src/_shims/openai_adapter.ts +446 -230
- package/src/_shims/register.js +16 -3
- package/src/assistant/gate.ts +15 -0
- package/src/assistant/index.ts +89 -0
- package/src/bootstrap/state.ts +6 -1
- package/src/bridge/peerSessions.ts +18 -0
- package/src/cli/print.ts +5 -0
- package/src/commands/assistant/assistant.ts +17 -0
- package/src/commands/assistant/index.ts +11 -0
- package/src/commands/brief.ts +3 -1
- package/src/commands/buddy/buddy.ts +88 -0
- package/src/commands/buddy/index.ts +12 -0
- package/src/commands/model/model.tsx +8 -23
- package/src/commands/peers/index.ts +11 -0
- package/src/commands/peers/peers.ts +24 -0
- package/src/commands/proactive/proactive.ts +64 -0
- package/src/commands/proactive.ts +12 -0
- package/src/commands/workflows/index.ts +12 -0
- package/src/commands/workflows/workflows.ts +36 -0
- package/src/commands.ts +4 -8
- package/src/components/Messages.tsx +1 -1
- package/src/components/ModelPicker.tsx +4 -34
- package/src/components/Spinner.tsx +54 -1
- package/src/components/StructuredDiff/colorDiff.ts +3 -1
- package/src/components/messages/SnipBoundaryMessage.tsx +15 -0
- package/src/components/messages/UserCrossSessionMessage.tsx +26 -0
- package/src/components/permissions/PermissionRequest.tsx +4 -2
- package/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.tsx +96 -0
- package/src/constants/prompts.ts +26 -0
- package/src/ink/terminal.ts +9 -1
- package/src/jobs/classifier.ts +103 -0
- package/src/memdir/paths.ts +13 -1
- package/src/proactive/index.ts +158 -0
- package/src/proactive/useProactive.ts +78 -0
- package/src/screens/REPL.tsx +28 -8
- package/src/services/api/claude.ts +6 -1
- package/src/services/compact/autoCompact.ts +18 -4
- package/src/services/compact/cachedMCConfig.ts +1 -0
- package/src/services/compact/cachedMicrocompact.ts +113 -0
- package/src/services/compact/compact.ts +22 -2
- package/src/services/compact/reactiveCompact.ts +251 -0
- package/src/services/compact/snipCompact.ts +282 -0
- package/src/services/compact/snipProjection.ts +50 -0
- package/src/services/contextCollapse/index.ts +322 -0
- package/src/services/contextCollapse/operations.ts +187 -0
- package/src/services/contextCollapse/persist.ts +40 -0
- package/src/services/extractMemories/extractMemories.ts +11 -2
- package/src/services/skillSearch/featureCheck.ts +12 -0
- package/src/services/skillSearch/localSearch.ts +98 -0
- package/src/services/skillSearch/prefetch.ts +125 -0
- package/src/services/skillSearch/remoteSkillLoader.ts +9 -0
- package/src/services/skillSearch/remoteSkillState.ts +21 -0
- package/src/services/skillSearch/signals.ts +7 -0
- package/src/services/skillSearch/telemetry.ts +9 -0
- package/src/setup.ts +10 -5
- package/src/skills/bundled/dream.ts +31 -0
- package/src/skills/bundled/hunter.ts +45 -0
- package/src/skills/bundled/index.ts +10 -23
- package/src/skills/bundled/runSkillGenerator.ts +61 -0
- package/src/skills/mcpSkills.ts +101 -0
- package/src/tasks/LocalWorkflowTask/LocalWorkflowTask.ts +301 -0
- package/src/tasks/MonitorMcpTask/MonitorMcpTask.ts +273 -0
- package/src/tasks.ts +22 -8
- package/src/tools/AgentTool/runAgent.ts +11 -0
- package/src/tools/BriefTool/BriefTool.ts +2 -0
- package/src/tools/CtxInspectTool/CtxInspectTool.ts +102 -0
- package/src/tools/DiscoverSkillsTool/DiscoverSkillsTool.ts +78 -0
- package/src/tools/DiscoverSkillsTool/prompt.ts +3 -0
- package/src/tools/ListPeersTool/ListPeersTool.ts +89 -0
- package/src/tools/MCPTool/MCPTool.ts +6 -0
- package/src/tools/MonitorTool/MonitorTool.ts +273 -0
- package/src/tools/MonitorTool/UI.tsx +25 -0
- package/src/tools/MonitorTool/events.ts +84 -0
- package/src/tools/MonitorTool/prompt.ts +45 -0
- package/src/tools/OverflowTestTool/OverflowTestTool.ts +73 -0
- package/src/tools/PushNotificationTool/PushNotificationTool.ts +119 -0
- package/src/tools/ReviewArtifactTool/ReviewArtifactTool.ts +93 -0
- package/src/tools/ReviewArtifactTool/prompt.ts +5 -0
- package/src/tools/SendUserFileTool/SendUserFileTool.ts +87 -0
- package/src/tools/SendUserFileTool/prompt.ts +7 -0
- package/src/tools/SleepTool/SleepTool.ts +126 -0
- package/src/tools/SnipTool/SnipTool.ts +90 -0
- package/src/tools/SnipTool/prompt.ts +5 -0
- package/src/tools/SubscribePRTool/SubscribePRTool.ts +115 -0
- package/src/tools/TerminalCaptureTool/TerminalCaptureTool.ts +129 -0
- package/src/tools/TerminalCaptureTool/prompt.ts +8 -0
- package/src/tools/ToolSearchTool/prompt.ts +1 -1
- package/src/tools/VerifyPlanExecutionTool/VerifyPlanExecutionTool.ts +99 -0
- package/src/tools/WebBrowserTool/WebBrowserPanel.tsx +10 -0
- package/src/tools/WebBrowserTool/WebBrowserTool.ts +190 -0
- package/src/tools/WebBrowserTool/prompt.ts +16 -0
- package/src/tools/WorkflowTool/UI.tsx +27 -0
- package/src/tools/WorkflowTool/WorkflowTool.ts +401 -0
- package/src/tools/WorkflowTool/bundled/index.ts +88 -0
- package/src/tools/WorkflowTool/constants.ts +7 -0
- package/src/tools/WorkflowTool/createWorkflowCommand.ts +84 -0
- package/src/tools/WorkflowTool/prompt.ts +38 -0
- package/src/tools/WorkflowTool/runtime.ts +331 -0
- package/src/tools.ts +36 -31
- package/src/utils/betas.ts +5 -0
- package/src/utils/context.ts +9 -0
- package/src/utils/conversationRecovery.ts +1 -1
- package/src/utils/forkedAgent.ts +4 -0
- package/src/utils/logoV2Utils.ts +7 -3
- package/src/utils/messageQueueManager.ts +23 -9
- package/src/utils/model/model.ts +10 -9
- package/src/utils/model/modelOptions.ts +0 -21
- package/src/utils/model/validateModel.ts +0 -19
- package/src/utils/permissions/permissionSetup.ts +5 -0
- package/src/utils/permissions/permissions.ts +25 -0
- package/src/utils/permissions/yolo-classifier-prompts/auto_mode_system_prompt.txt +38 -0
- package/src/utils/permissions/yolo-classifier-prompts/permissions_external.txt +25 -0
- package/src/utils/permissions/yoloClassifier.ts +28 -6
- package/src/utils/plugins/officialMarketplaceStartupCheck.ts +9 -0
- package/src/utils/systemThemeWatcher.ts +62 -0
- package/src/utils/udsClient.ts +115 -0
- package/src/utils/udsMessaging.ts +157 -0
- package/src/utils/yaml.ts +251 -5
- package/src/utils/model/providerModels.ts +0 -168
package/src/_shims/bun_bundle.js
CHANGED
|
@@ -1,8 +1,83 @@
|
|
|
1
1
|
// Shim for bun:bundle - replaces build-time feature flags with runtime config
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
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);
|
package/src/_shims/cjs_stub.cjs
CHANGED
|
@@ -1,23 +1,45 @@
|
|
|
1
|
-
// CJS stub for missing/DCE'd modules
|
|
2
|
-
//
|
|
3
|
-
|
|
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
|
-
|
|
6
|
-
|
|
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
|
|
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
|
-
|
|
18
|
-
|
|
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;
|
package/src/_shims/loader.js
CHANGED
|
@@ -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
|
-
|
|
235
|
-
|
|
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.
|
|
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.
|
|
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(')) {
|