@selesai/code 0.13.26 → 0.13.27
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/CHANGELOG.md +74 -0
- package/dist/cli/args.js +1 -0
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/core/agent-session-auto-handoff.test.js +2 -1
- package/dist/core/agent-session-length-continuation.test.js +2 -1
- package/dist/core/agent-session.d.ts +58 -7
- package/dist/core/agent-session.js +334 -167
- package/dist/core/bug-report-upload.d.ts +11 -0
- package/dist/core/bug-report-upload.js +21 -0
- package/dist/core/bug-report.d.ts +175 -0
- package/dist/core/bug-report.js +291 -0
- package/dist/core/cache-stats.js +12 -1
- package/dist/core/cache-warmer.d.ts +101 -0
- package/dist/core/cache-warmer.js +341 -0
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/compaction.d.ts +6 -5
- package/dist/core/compaction/compaction.js +49 -42
- package/dist/core/crash-log.d.ts +21 -0
- package/dist/core/crash-log.js +70 -0
- package/dist/core/experimental.d.ts +0 -4
- package/dist/core/experimental.js +0 -4
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/jiti-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-loader.js +3 -0
- package/dist/core/extensions/jiti-static-loader.d.ts +1 -0
- package/dist/core/extensions/jiti-static-loader.js +3 -0
- package/dist/core/extensions/loader.js +39 -49
- package/dist/core/extensions/runner.d.ts +10 -7
- package/dist/core/extensions/runner.js +85 -67
- package/dist/core/extensions/types.d.ts +66 -52
- package/dist/core/extensions/virtual-modules.d.ts +2 -0
- package/dist/core/extensions/virtual-modules.js +39 -0
- package/dist/core/extensions/wrapper.js +1 -20
- package/dist/core/index.d.ts +2 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/messages.js +1 -0
- package/dist/core/model-config.d.ts +101 -20
- package/dist/core/model-config.js +25 -18
- package/dist/core/model-resolver.js +2 -1
- package/dist/core/model-runtime.js +5 -3
- package/dist/core/provider-composer.d.ts +7 -2
- package/dist/core/provider-composer.js +10 -5
- package/dist/core/radius.d.ts +3 -0
- package/dist/core/radius.js +6 -0
- package/dist/core/sdk.js +60 -38
- package/dist/core/session-export.d.ts +6 -2
- package/dist/core/session-export.js +14 -13
- package/dist/core/session-format.test.d.ts +1 -0
- package/dist/core/session-format.test.js +96 -0
- package/dist/core/session-manager.d.ts +29 -6
- package/dist/core/session-manager.js +159 -96
- package/dist/core/settings-manager.d.ts +22 -5
- package/dist/core/settings-manager.js +56 -23
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/system-prompt.d.ts +49 -4
- package/dist/core/system-prompt.js +155 -102
- package/dist/core/system-prompt.test.js +61 -23
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.js +10 -4
- package/dist/core/tools/edit.js +1 -2
- package/dist/core/tools/read.js +1 -2
- package/dist/core/tools/renderers/bash.js +9 -1
- package/dist/core/tools/write.js +1 -2
- package/dist/core/usage-totals.d.ts +1 -1
- package/dist/core/usage-totals.js +5 -1
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +14 -6
- package/dist/extensions/pi-web-agent/src/extension.ts +3 -1
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +7 -3
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +3 -0
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +2 -0
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +4 -2
- package/dist/extensions/pi-web-agent/src/search/tokenin.ts +4 -1
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +2 -1
- package/dist/extensions/pi-web-agent/src/types.ts +4 -0
- package/dist/index.d.ts +3 -2
- package/dist/main.js +13 -9
- package/dist/migrations.js +2 -2
- package/dist/modes/interactive/bug-report.d.ts +15 -0
- package/dist/modes/interactive/bug-report.js +205 -0
- package/dist/modes/interactive/chat-viewport.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +12 -5
- package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
- package/dist/modes/interactive/components/extension-editor.js +7 -2
- package/dist/modes/interactive/components/extension-input.d.ts +2 -0
- package/dist/modes/interactive/components/extension-input.js +6 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/components/footer.js +4 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.js +74 -48
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.js +11 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
- package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
- package/dist/modes/interactive/components/status-indicator.js +7 -7
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tree-selector.js +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts +15 -2
- package/dist/modes/interactive/interactive-mode.js +257 -81
- package/dist/modes/interactive/session-share.d.ts +2 -0
- package/dist/modes/interactive/session-share.js +8 -4
- package/dist/modes/interactive/tui-renderer.js +2 -2
- package/dist/modes/rpc/rpc-mode.js +2 -2
- package/dist/utils/clipboard-command.d.ts +6 -0
- package/dist/utils/clipboard-command.js +44 -0
- package/dist/utils/clipboard-image.js +55 -89
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.js +118 -108
- package/dist/utils/wsl.d.ts +2 -0
- package/dist/utils/wsl.js +14 -0
- package/dist/utils/zip.d.ts +6 -0
- package/dist/utils/zip.js +59 -0
- package/package.json +9 -9
- package/dist/utils/clipboard-native.d.ts +0 -10
- package/dist/utils/clipboard-native.js +0 -19
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { getAgentDir, VERSION } from "../config.js";
|
|
4
|
+
const MAX_CRASH_RECORDS = 5;
|
|
5
|
+
const MAX_AGE = 7 * 24 * 60 * 60 * 1000;
|
|
6
|
+
function crashLogPath(agentDir = getAgentDir()) {
|
|
7
|
+
return join(agentDir, "crashes.json");
|
|
8
|
+
}
|
|
9
|
+
export function readCrashLog(path = crashLogPath()) {
|
|
10
|
+
try {
|
|
11
|
+
const records = JSON.parse(readFileSync(path, "utf8"));
|
|
12
|
+
return Array.isArray(records)
|
|
13
|
+
? records.filter((record) => typeof record === "object" &&
|
|
14
|
+
record !== null &&
|
|
15
|
+
typeof record.timestamp === "string" &&
|
|
16
|
+
typeof record.message === "string")
|
|
17
|
+
: [];
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function writeCrashLog(records, path) {
|
|
24
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
25
|
+
writeFileSync(path, `${JSON.stringify(records, null, 2)}\n`);
|
|
26
|
+
}
|
|
27
|
+
/** Best-effort persistence for callers that are already crashing. */
|
|
28
|
+
export function recordCrash(crash, path = crashLogPath()) {
|
|
29
|
+
try {
|
|
30
|
+
const { error } = crash;
|
|
31
|
+
const record = {
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
|
+
version: VERSION,
|
|
34
|
+
kind: crash.kind,
|
|
35
|
+
message: error instanceof Error ? error.message || error.name : String(error),
|
|
36
|
+
stack: error instanceof Error && error.stack ? error.stack : null,
|
|
37
|
+
sessionFile: crash.sessionFile ?? null,
|
|
38
|
+
cwd: crash.cwd,
|
|
39
|
+
};
|
|
40
|
+
writeCrashLog([...readCrashLog(path), record].slice(-MAX_CRASH_RECORDS), path);
|
|
41
|
+
return record;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Return the newest recent crash, marking pending records as announced. */
|
|
48
|
+
export function takeUnnotifiedCrash(path = crashLogPath(), now = Date.now()) {
|
|
49
|
+
const records = readCrashLog(path);
|
|
50
|
+
const crash = [...records]
|
|
51
|
+
.reverse()
|
|
52
|
+
.find((record) => !record.notified && now - Date.parse(record.timestamp) <= MAX_AGE);
|
|
53
|
+
if (!crash)
|
|
54
|
+
return undefined;
|
|
55
|
+
try {
|
|
56
|
+
writeCrashLog(records.map((record) => (record.notified ? record : { ...record, notified: true })), path);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Showing the notice again is harmless.
|
|
60
|
+
}
|
|
61
|
+
return crash;
|
|
62
|
+
}
|
|
63
|
+
export function clearCrashLog(path = crashLogPath()) {
|
|
64
|
+
try {
|
|
65
|
+
rmSync(path, { force: true });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// The records can be attached again if cleanup fails.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
const PREFER_STRICT_TOOL_SAMPLING = { type: "json_schema", strict: "prefer" };
|
|
2
1
|
export function areExperimentalFeaturesEnabled() {
|
|
3
2
|
return process.env.PI_EXPERIMENTAL === "1";
|
|
4
3
|
}
|
|
5
|
-
export function getExperimentalToolSampling() {
|
|
6
|
-
return areExperimentalFeaturesEnabled() ? PREFER_STRICT_TOOL_SAMPLING : undefined;
|
|
7
|
-
}
|
|
@@ -6,6 +6,6 @@ export type { SourceInfo } from "../source-info.ts";
|
|
|
6
6
|
export { createExtensionRuntime, discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions, } from "./loader.ts";
|
|
7
7
|
export type { ExtensionErrorListener, ForkHandler, NavigateTreeHandler, NewSessionHandler, ShutdownHandler, SwitchSessionHandler, } from "./runner.ts";
|
|
8
8
|
export { ExtensionRunner } from "./runner.ts";
|
|
9
|
-
export type { AfterProviderResponseEvent, AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppendEntryHandler, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BuildSystemPromptOptions, CompactOptions, ContextEvent, ContextEventResult, ContextUsage, CustomToolCallEvent, CustomToolResultEvent, EditorFactory, EditToolCallEvent, EditToolResultEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionMode, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GetCommandsHandler, GetThinkingLevelHandler, GrepToolCallEvent, GrepToolResultEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, LsToolResultEvent, MessageEndEvent, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, ReadToolResultEvent, RegisteredCommand, RegisteredTool, ReplacedSessionContext, ResolvedCommand, ResolvedSkillInfo, ResourcesDiscoverEvent, ResourcesDiscoverResult, SendMessageHandler, SendUserMessageHandler, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionCompactEvent, SessionEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SetActiveToolsHandler, SetLabelHandler, SetModelHandler, SetThinkingLevelHandler, TerminalInputHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, WriteToolResultEvent, } from "./types.ts";
|
|
9
|
+
export type { AfterProviderResponseEvent, AgentEndEvent, AgentSettledEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppendEntryHandler, AppKeybinding, AutocompleteProviderFactory, BashToolCallEvent, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, BeforeProviderRequestEventResult, BuildSystemPromptOptions, CacheWarmingDecisionEvent, CacheWarmingDecisionEventResult, CompactOptions, ContextEvent, ContextEventResult, ContextUsage, CustomToolCallEvent, CustomToolResultEvent, EditorFactory, EditToolCallEvent, EditToolResultEvent, EntryRenderer, EntryRenderOptions, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionMode, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GetCommandsHandler, GetThinkingLevelHandler, GrepToolCallEvent, GrepToolResultEvent, InlineExtension, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, LsToolResultEvent, MessageEndEvent, MessageEndEventResult, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, MarkdownTransformContext, MarkdownTransformer, NormalizedBuildSystemPromptOptions, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventDecision, ProjectTrustEventResult, ProjectTrustHandler, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, ReadToolResultEvent, RegisteredCommand, RegisteredTool, ReplacedSessionContext, ResolvedCommand, ResolvedSkillInfo, ResourcesDiscoverEvent, ResourcesDiscoverResult, SendMessageHandler, SendUserMessageHandler, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionCompactEvent, SessionCompactFailedEvent, SessionEvent, SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, SetActiveToolsHandler, SetLabelHandler, SetModelHandler, SetThinkingLevelHandler, TerminalInputHandler, ThinkingLevelSelectEvent, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionMode, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, UIPromptEndEvent, UIPromptKind, UIPromptStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WorkingIndicatorOptions, WriteToolCallEvent, WriteToolResultEvent, } from "./types.ts";
|
|
10
10
|
export { defineTool, isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, } from "./types.ts";
|
|
11
11
|
export { wrapRegisteredTool, wrapRegisteredTools } from "./wrapper.ts";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createJiti } from "jiti";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createJiti } from "jiti/static";
|
|
@@ -6,58 +6,27 @@ import * as fs from "node:fs";
|
|
|
6
6
|
import { createRequire } from "node:module";
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import
|
|
10
|
-
import * as _bundledPiAiCompat from "@earendil-works/pi-ai/compat";
|
|
11
|
-
import * as _bundledPiAiOauth from "@earendil-works/pi-ai/oauth";
|
|
12
|
-
import * as _bundledPiAiProviders from "@earendil-works/pi-ai/providers/all";
|
|
13
|
-
import * as _bundledPiTui from "@earendil-works/pi-tui";
|
|
14
|
-
import { createJiti } from "jiti/static";
|
|
15
|
-
// Static imports of packages that extensions may use.
|
|
16
|
-
// These MUST be static so Bun bundles them into the compiled binary.
|
|
17
|
-
// The virtualModules option then makes them available to extensions.
|
|
18
|
-
import * as _bundledTypebox from "typebox";
|
|
19
|
-
import * as _bundledTypeboxCompile from "typebox/compile";
|
|
20
|
-
import * as _bundledTypeboxValue from "typebox/value";
|
|
21
|
-
import { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from "../../config.js";
|
|
22
|
-
// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,
|
|
23
|
-
// avoiding a circular dependency. Extensions can import from @earendil-works/pi-coding-agent.
|
|
24
|
-
import * as _bundledPiCodingAgent from "../../index.js";
|
|
9
|
+
import { CONFIG_DIR_NAME, getAgentDir, isBunBinary, isBundledNode } from "../../config.js";
|
|
25
10
|
import { resolvePath } from "../../utils/paths.js";
|
|
26
11
|
import { createEventBus } from "../event-bus.js";
|
|
27
12
|
import { execCommand } from "../exec.js";
|
|
28
13
|
import { createSyntheticSourceInfo } from "../source-info.js";
|
|
29
14
|
import { time } from "../timings.js";
|
|
30
|
-
/** Modules available to extensions via virtualModules (for compiled Bun binary) */
|
|
31
|
-
const VIRTUAL_MODULES = {
|
|
32
|
-
typebox: _bundledTypebox,
|
|
33
|
-
"typebox/compile": _bundledTypeboxCompile,
|
|
34
|
-
"typebox/value": _bundledTypeboxValue,
|
|
35
|
-
"@sinclair/typebox": _bundledTypebox,
|
|
36
|
-
"@sinclair/typebox/compile": _bundledTypeboxCompile,
|
|
37
|
-
"@sinclair/typebox/value": _bundledTypeboxValue,
|
|
38
|
-
"@earendil-works/pi-agent-core": _bundledPiAgentCore,
|
|
39
|
-
"@earendil-works/pi-tui": _bundledPiTui,
|
|
40
|
-
// Extensions resolve the pi-ai root to the compat entrypoint (a strict
|
|
41
|
-
// superset of the core entrypoint): existing extensions using the old
|
|
42
|
-
// global API keep working at runtime until compat is removed.
|
|
43
|
-
"@earendil-works/pi-ai": _bundledPiAiCompat,
|
|
44
|
-
"@earendil-works/pi-ai/compat": _bundledPiAiCompat,
|
|
45
|
-
"@earendil-works/pi-ai/oauth": _bundledPiAiOauth,
|
|
46
|
-
"@earendil-works/pi-ai/providers/all": _bundledPiAiProviders,
|
|
47
|
-
"@earendil-works/pi-coding-agent": _bundledPiCodingAgent,
|
|
48
|
-
"@selesai/code": _bundledPiCodingAgent,
|
|
49
|
-
"@mariozechner/pi-agent-core": _bundledPiAgentCore,
|
|
50
|
-
"@mariozechner/pi-tui": _bundledPiTui,
|
|
51
|
-
"@mariozechner/pi-ai": _bundledPiAiCompat,
|
|
52
|
-
"@mariozechner/pi-ai/compat": _bundledPiAiCompat,
|
|
53
|
-
"@mariozechner/pi-ai/oauth": _bundledPiAiOauth,
|
|
54
|
-
"@mariozechner/pi-ai/providers/all": _bundledPiAiProviders,
|
|
55
|
-
"@mariozechner/pi-coding-agent": _bundledPiCodingAgent,
|
|
56
|
-
};
|
|
57
15
|
const require = createRequire(import.meta.url);
|
|
58
16
|
const isNodeSeaBinary = ("sea" in process.features && process.features.sea === true) ||
|
|
59
17
|
process.getBuiltinModule("node:sea")?.isSea() === true;
|
|
60
18
|
const isTypeScriptSourceRuntime = !isBunBinary && path.extname(fileURLToPath(import.meta.url)) === ".ts";
|
|
19
|
+
const usesEmbeddedModules = isBunBinary || isNodeSeaBinary || isBundledNode;
|
|
20
|
+
let createJitiPromise;
|
|
21
|
+
function getCreateJiti() {
|
|
22
|
+
createJitiPromise ??= (usesEmbeddedModules ? import("./jiti-static-loader.js") : import("./jiti-loader.js")).then((module) => module.createJiti);
|
|
23
|
+
return createJitiPromise;
|
|
24
|
+
}
|
|
25
|
+
let virtualModulesPromise;
|
|
26
|
+
function getVirtualModules() {
|
|
27
|
+
virtualModulesPromise ??= import("./virtual-modules.js").then((module) => module.VIRTUAL_MODULES);
|
|
28
|
+
return virtualModulesPromise;
|
|
29
|
+
}
|
|
61
30
|
/**
|
|
62
31
|
* Get aliases for jiti (used in Node.js/development mode).
|
|
63
32
|
* In Bun binary mode, virtualModules is used instead.
|
|
@@ -210,12 +179,27 @@ function createExtensionAPI(extension, runtime, cwd, eventBus) {
|
|
|
210
179
|
// Registration methods - write to extension
|
|
211
180
|
on(event, handler) {
|
|
212
181
|
assertActive();
|
|
182
|
+
const registeredHandler = (...args) => handler(...args);
|
|
213
183
|
const list = extension.handlers.get(event) ?? [];
|
|
214
|
-
list.push(
|
|
184
|
+
list.push(registeredHandler);
|
|
215
185
|
extension.handlers.set(event, list);
|
|
186
|
+
return () => {
|
|
187
|
+
const handlers = extension.handlers.get(event);
|
|
188
|
+
if (!handlers)
|
|
189
|
+
return;
|
|
190
|
+
const handlerIndex = handlers.indexOf(registeredHandler);
|
|
191
|
+
if (handlerIndex === -1)
|
|
192
|
+
return;
|
|
193
|
+
handlers.splice(handlerIndex, 1);
|
|
194
|
+
if (handlers.length === 0)
|
|
195
|
+
extension.handlers.delete(event);
|
|
196
|
+
};
|
|
216
197
|
},
|
|
217
198
|
registerTool(tool) {
|
|
218
199
|
assertActive();
|
|
200
|
+
if (typeof tool.parameters !== "object" || tool.parameters === null || Array.isArray(tool.parameters)) {
|
|
201
|
+
throw new Error(`Tool "${tool.name}" registered by extension "${extension.path}" must define an object parameter schema.`);
|
|
202
|
+
}
|
|
219
203
|
extension.tools.set(tool.name, {
|
|
220
204
|
definition: tool,
|
|
221
205
|
sourceInfo: extension.sourceInfo,
|
|
@@ -396,12 +380,18 @@ async function loadExtensionModule(extensionPath, cacheToken) {
|
|
|
396
380
|
return cachedFactory;
|
|
397
381
|
}
|
|
398
382
|
}
|
|
399
|
-
const
|
|
383
|
+
const createJitiImpl = await getCreateJiti();
|
|
384
|
+
// Compiled binaries and the bundled Node distribution use embedded modules.
|
|
385
|
+
// Source TypeScript reuses host modules and root tsconfig paths. Unbundled
|
|
386
|
+
// Node builds use dist aliases and do not need the bundled virtual modules.
|
|
387
|
+
const resolutionOptions = usesEmbeddedModules
|
|
388
|
+
? { virtualModules: await getVirtualModules(), tryNative: false }
|
|
389
|
+
: isTypeScriptSourceRuntime
|
|
390
|
+
? { virtualModules: await getVirtualModules(), tsconfigPaths: true }
|
|
391
|
+
: { alias: getAliases() };
|
|
392
|
+
const jiti = createJitiImpl(import.meta.url, {
|
|
400
393
|
moduleCache: false,
|
|
401
|
-
|
|
402
|
-
// Also disable tryNative so jiti handles ALL imports (not just the entry point)
|
|
403
|
-
// In Node.js/dev: use aliases to resolve to node_modules paths
|
|
404
|
-
...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),
|
|
394
|
+
...resolutionOptions,
|
|
405
395
|
});
|
|
406
396
|
const module = await jiti.import(extensionPath, { default: true });
|
|
407
397
|
const factory = module;
|
|
@@ -4,22 +4,23 @@
|
|
|
4
4
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
5
5
|
import type { ImageContent, Provider, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
6
6
|
import type { KeyId } from "@earendil-works/pi-tui";
|
|
7
|
+
import type { CacheWarmingAction } from "../cache-warmer.ts";
|
|
7
8
|
import type { ResourceDiagnostic } from "../diagnostics.ts";
|
|
8
9
|
import type { KeybindingsConfig } from "../keybindings.ts";
|
|
9
10
|
import type { ModelRegistry } from "../model-registry.ts";
|
|
10
11
|
import type { SessionManager } from "../session-manager.ts";
|
|
11
|
-
import type
|
|
12
|
-
import type { BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, ContextEvent, EntryRenderer, Extension, ExtensionActions, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionMode, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, InputEvent, InputEventResult, InputSource, LoadExtensionsResult, MessageEndEvent, MessageRenderer, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventResult, ProviderConfig, RegisteredTool, ReplacedSessionContext, ResolvedCommand, ResourcesDiscoverEvent, SessionBeforeCompactResult, SessionBeforeForkResult, SessionBeforeSwitchResult, SessionBeforeTreeResult, SessionShutdownEvent, ToolCallEvent, ToolCallEventResult, ToolResultEvent, ToolResultEventResult, UserBashEvent, UserBashEventResult } from "./types.ts";
|
|
13
|
-
/** Combined result from all before_agent_start handlers */
|
|
12
|
+
import { type BuildSystemPromptOptions, type NormalizedBuildSystemPromptOptions } from "../system-prompt.ts";
|
|
13
|
+
import type { BeforeAgentStartEvent, BeforeAgentStartEventResult, BeforeProviderHeadersEvent, BeforeProviderRequestEvent, CacheWarmingDecisionEvent, ContextEvent, EntryRenderer, Extension, ExtensionActions, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionMode, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, InputEvent, InputEventResult, InputSource, LoadExtensionsResult, MessageEndEvent, MessageRenderer, ProjectTrustContext, ProjectTrustEvent, ProjectTrustEventResult, ProviderConfig, RegisteredTool, ReplacedSessionContext, ResolvedCommand, ResourcesDiscoverEvent, SessionBeforeCompactResult, SessionBeforeForkResult, SessionBeforeSwitchResult, SessionBeforeTreeResult, SessionShutdownEvent, ToolCallEvent, ToolCallEventResult, ToolResultEvent, ToolResultEventResult, UserBashEvent, UserBashEventResult } from "./types.ts";
|
|
14
|
+
/** Combined result from all before_agent_start handlers. */
|
|
14
15
|
interface BeforeAgentStartCombinedResult {
|
|
15
|
-
messages
|
|
16
|
-
|
|
16
|
+
messages: NonNullable<BeforeAgentStartEventResult["message"]>[];
|
|
17
|
+
systemPromptOptions: NormalizedBuildSystemPromptOptions;
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Events handled by the generic emit() method.
|
|
20
21
|
* Events with dedicated emitXxx() methods are excluded for stronger type safety.
|
|
21
22
|
*/
|
|
22
|
-
type RunnerEmitEvent = Exclude<ExtensionEvent, ToolCallEvent | ProjectTrustEvent | ToolResultEvent | UserBashEvent | ContextEvent | BeforeProviderRequestEvent | BeforeProviderHeadersEvent | BeforeAgentStartEvent | MessageEndEvent | ResourcesDiscoverEvent | InputEvent>;
|
|
23
|
+
type RunnerEmitEvent = Exclude<ExtensionEvent, ToolCallEvent | ProjectTrustEvent | ToolResultEvent | UserBashEvent | ContextEvent | CacheWarmingDecisionEvent | BeforeProviderRequestEvent | BeforeProviderHeadersEvent | BeforeAgentStartEvent | MessageEndEvent | ResourcesDiscoverEvent | InputEvent>;
|
|
23
24
|
type RunnerEmitResult<TEvent extends RunnerEmitEvent> = TEvent extends {
|
|
24
25
|
type: "session_before_switch";
|
|
25
26
|
} ? SessionBeforeSwitchResult | undefined : TEvent extends {
|
|
@@ -148,6 +149,8 @@ export declare class ExtensionRunner {
|
|
|
148
149
|
createCommandContext(): ExtensionCommandContext;
|
|
149
150
|
private isSessionBeforeEvent;
|
|
150
151
|
emit<TEvent extends RunnerEmitEvent>(event: TEvent): Promise<RunnerEmitResult<TEvent>>;
|
|
152
|
+
/** Returns the event's own action unless a handler overrides it; the last override wins. */
|
|
153
|
+
emitCacheWarmingDecision(event: CacheWarmingDecisionEvent): Promise<CacheWarmingAction>;
|
|
151
154
|
emitMessageEnd(event: MessageEndEvent): Promise<AgentMessage | undefined>;
|
|
152
155
|
emitToolResult(event: ToolResultEvent): Promise<ToolResultEventResult | undefined>;
|
|
153
156
|
emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined>;
|
|
@@ -155,7 +158,7 @@ export declare class ExtensionRunner {
|
|
|
155
158
|
emitContext(messages: AgentMessage[]): Promise<AgentMessage[]>;
|
|
156
159
|
emitBeforeProviderRequest(payload: unknown): Promise<unknown>;
|
|
157
160
|
emitBeforeProviderHeaders(headers: ProviderHeaders): Promise<ProviderHeaders>;
|
|
158
|
-
emitBeforeAgentStart(prompt: string, images: ImageContent[] | undefined,
|
|
161
|
+
emitBeforeAgentStart(prompt: string, images: ImageContent[] | undefined, systemPromptOptions: BuildSystemPromptOptions): Promise<BeforeAgentStartCombinedResult>;
|
|
159
162
|
emitResourcesDiscover(cwd: string, reason: ResourcesDiscoverEvent["reason"]): Promise<{
|
|
160
163
|
skillPaths: Array<{
|
|
161
164
|
path: string;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Extension runner - executes extensions and manages their lifecycle.
|
|
3
3
|
*/
|
|
4
4
|
import { theme } from "../../modes/interactive/theme/theme.js";
|
|
5
|
+
import { buildSystemPrompt, normalizeBuildSystemPromptOptions, } from "../system-prompt.js";
|
|
5
6
|
// Extension shortcuts compete with canonical keybinding ids from keybindings.json.
|
|
6
7
|
// Only editor-global shortcuts are reserved here. Picker-specific bindings are not.
|
|
7
8
|
const RESERVED_KEYBINDINGS_FOR_EXTENSION_CONFLICTS = [
|
|
@@ -46,6 +47,31 @@ const buildBuiltinKeybindings = (resolvedKeybindings) => {
|
|
|
46
47
|
}
|
|
47
48
|
return builtinKeybindings;
|
|
48
49
|
};
|
|
50
|
+
function isUserBashEventResult(value) {
|
|
51
|
+
if (typeof value !== "object" || value === null)
|
|
52
|
+
return false;
|
|
53
|
+
const candidate = value;
|
|
54
|
+
const hasOperations = candidate.operations !== undefined;
|
|
55
|
+
const hasResult = candidate.result !== undefined;
|
|
56
|
+
if (hasOperations === hasResult)
|
|
57
|
+
return false;
|
|
58
|
+
if (hasOperations) {
|
|
59
|
+
const operations = candidate.operations;
|
|
60
|
+
if (typeof operations !== "object" || operations === null)
|
|
61
|
+
return false;
|
|
62
|
+
return typeof operations.exec === "function";
|
|
63
|
+
}
|
|
64
|
+
const result = candidate.result;
|
|
65
|
+
if (typeof result !== "object" || result === null)
|
|
66
|
+
return false;
|
|
67
|
+
const resultRecord = result;
|
|
68
|
+
return (typeof resultRecord.output === "string" &&
|
|
69
|
+
"exitCode" in resultRecord &&
|
|
70
|
+
(resultRecord.exitCode === undefined || typeof resultRecord.exitCode === "number") &&
|
|
71
|
+
typeof resultRecord.cancelled === "boolean" &&
|
|
72
|
+
typeof resultRecord.truncated === "boolean" &&
|
|
73
|
+
(resultRecord.fullOutputPath === undefined || typeof resultRecord.fullOutputPath === "string"));
|
|
74
|
+
}
|
|
49
75
|
/**
|
|
50
76
|
* Helper function to emit session_shutdown event to extensions.
|
|
51
77
|
* Returns true if the event was emitted, false if there were no handlers.
|
|
@@ -57,14 +83,14 @@ export async function emitSessionShutdownEvent(extensionRunner, event) {
|
|
|
57
83
|
}
|
|
58
84
|
return false;
|
|
59
85
|
}
|
|
86
|
+
function snapshotEventHandlers(extensions, event) {
|
|
87
|
+
return extensions.map((ext) => ({ ext, handlers: ext.handlers.get(event)?.slice() ?? [] }));
|
|
88
|
+
}
|
|
60
89
|
export async function emitProjectTrustEvent(extensionsResult, event, ctx) {
|
|
61
90
|
const errors = [];
|
|
62
|
-
for (const ext of extensionsResult.extensions) {
|
|
91
|
+
for (const { ext, handlers } of snapshotEventHandlers(extensionsResult.extensions, "project_trust")) {
|
|
63
92
|
// A single extension may register multiple handlers for the same event.
|
|
64
93
|
// The first project_trust handler that returns yes/no wins; undecided falls through.
|
|
65
|
-
const handlers = ext.handlers.get("project_trust");
|
|
66
|
-
if (!handlers || handlers.length === 0)
|
|
67
|
-
continue;
|
|
68
94
|
for (const handler of handlers) {
|
|
69
95
|
try {
|
|
70
96
|
const handlerResult = (await handler(event, ctx));
|
|
@@ -139,7 +165,7 @@ export class ExtensionRunner {
|
|
|
139
165
|
getContextUsageFn = () => undefined;
|
|
140
166
|
compactFn = () => { };
|
|
141
167
|
getSystemPromptFn = () => "";
|
|
142
|
-
getSystemPromptOptionsFn = () => ({ cwd: this.cwd });
|
|
168
|
+
getSystemPromptOptionsFn = () => normalizeBuildSystemPromptOptions({ cwd: this.cwd });
|
|
143
169
|
newSessionHandler = async () => ({ cancelled: false });
|
|
144
170
|
forkHandler = async () => ({ cancelled: false });
|
|
145
171
|
navigateTreeHandler = async () => ({ cancelled: false });
|
|
@@ -187,7 +213,8 @@ export class ExtensionRunner {
|
|
|
187
213
|
this.getContextUsageFn = contextActions.getContextUsage;
|
|
188
214
|
this.compactFn = contextActions.compact;
|
|
189
215
|
this.getSystemPromptFn = contextActions.getSystemPrompt;
|
|
190
|
-
this.getSystemPromptOptionsFn =
|
|
216
|
+
this.getSystemPromptOptionsFn =
|
|
217
|
+
contextActions.getSystemPromptOptions ?? (() => normalizeBuildSystemPromptOptions({ cwd: this.cwd }));
|
|
191
218
|
// Flush provider registrations queued during extension loading
|
|
192
219
|
for (const { name, config, extensionPath } of this.runtime.pendingProviderRegistrations) {
|
|
193
220
|
try {
|
|
@@ -625,10 +652,7 @@ export class ExtensionRunner {
|
|
|
625
652
|
async emit(event) {
|
|
626
653
|
const ctx = this.createContext();
|
|
627
654
|
let result;
|
|
628
|
-
for (const ext of this.extensions) {
|
|
629
|
-
const handlers = ext.handlers.get(event.type);
|
|
630
|
-
if (!handlers || handlers.length === 0)
|
|
631
|
-
continue;
|
|
655
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, event.type)) {
|
|
632
656
|
for (const handler of handlers) {
|
|
633
657
|
try {
|
|
634
658
|
const handlerResult = await handler(event, ctx);
|
|
@@ -653,14 +677,34 @@ export class ExtensionRunner {
|
|
|
653
677
|
}
|
|
654
678
|
return result;
|
|
655
679
|
}
|
|
680
|
+
/** Returns the event's own action unless a handler overrides it; the last override wins. */
|
|
681
|
+
async emitCacheWarmingDecision(event) {
|
|
682
|
+
const ctx = this.createContext();
|
|
683
|
+
let action = event.action;
|
|
684
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, event.type)) {
|
|
685
|
+
for (const handler of handlers) {
|
|
686
|
+
try {
|
|
687
|
+
const result = (await handler(event, ctx));
|
|
688
|
+
if (result?.action !== undefined)
|
|
689
|
+
action = result.action;
|
|
690
|
+
}
|
|
691
|
+
catch (err) {
|
|
692
|
+
this.emitError({
|
|
693
|
+
extensionPath: ext.path,
|
|
694
|
+
event: event.type,
|
|
695
|
+
error: err instanceof Error ? err.message : String(err),
|
|
696
|
+
stack: err instanceof Error ? err.stack : undefined,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
return action;
|
|
702
|
+
}
|
|
656
703
|
async emitMessageEnd(event) {
|
|
657
704
|
const ctx = this.createContext();
|
|
658
705
|
let currentMessage = event.message;
|
|
659
706
|
let modified = false;
|
|
660
|
-
for (const ext of this.extensions) {
|
|
661
|
-
const handlers = ext.handlers.get("message_end");
|
|
662
|
-
if (!handlers || handlers.length === 0)
|
|
663
|
-
continue;
|
|
707
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "message_end")) {
|
|
664
708
|
for (const handler of handlers) {
|
|
665
709
|
try {
|
|
666
710
|
const currentEvent = { ...event, message: currentMessage };
|
|
@@ -697,10 +741,7 @@ export class ExtensionRunner {
|
|
|
697
741
|
const currentEvent = { ...event };
|
|
698
742
|
let modified = false;
|
|
699
743
|
let terminate;
|
|
700
|
-
for (const ext of this.extensions) {
|
|
701
|
-
const handlers = ext.handlers.get("tool_result");
|
|
702
|
-
if (!handlers || handlers.length === 0)
|
|
703
|
-
continue;
|
|
744
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "tool_result")) {
|
|
704
745
|
for (const handler of handlers) {
|
|
705
746
|
try {
|
|
706
747
|
const handlerResult = (await handler(currentEvent, ctx));
|
|
@@ -753,10 +794,7 @@ export class ExtensionRunner {
|
|
|
753
794
|
async emitToolCall(event) {
|
|
754
795
|
const ctx = this.createContext();
|
|
755
796
|
let result;
|
|
756
|
-
for (const
|
|
757
|
-
const handlers = ext.handlers.get("tool_call");
|
|
758
|
-
if (!handlers || handlers.length === 0)
|
|
759
|
-
continue;
|
|
797
|
+
for (const { handlers } of snapshotEventHandlers(this.extensions, "tool_call")) {
|
|
760
798
|
for (const handler of handlers) {
|
|
761
799
|
const handlerResult = await handler(event, ctx);
|
|
762
800
|
if (handlerResult) {
|
|
@@ -771,16 +809,16 @@ export class ExtensionRunner {
|
|
|
771
809
|
}
|
|
772
810
|
async emitUserBash(event) {
|
|
773
811
|
const ctx = this.createContext();
|
|
774
|
-
for (const ext of this.extensions) {
|
|
775
|
-
const handlers = ext.handlers.get("user_bash");
|
|
776
|
-
if (!handlers || handlers.length === 0)
|
|
777
|
-
continue;
|
|
812
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "user_bash")) {
|
|
778
813
|
for (const handler of handlers) {
|
|
779
814
|
try {
|
|
780
815
|
const handlerResult = await handler(event, ctx);
|
|
781
|
-
if (handlerResult)
|
|
782
|
-
|
|
816
|
+
if (handlerResult === undefined)
|
|
817
|
+
continue;
|
|
818
|
+
if (!isUserBashEventResult(handlerResult)) {
|
|
819
|
+
throw new Error("Invalid user_bash handler result: return undefined for local execution or exactly one valid { operations } or { result } object");
|
|
783
820
|
}
|
|
821
|
+
return handlerResult;
|
|
784
822
|
}
|
|
785
823
|
catch (err) {
|
|
786
824
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -791,6 +829,7 @@ export class ExtensionRunner {
|
|
|
791
829
|
error: message,
|
|
792
830
|
stack,
|
|
793
831
|
});
|
|
832
|
+
throw err;
|
|
794
833
|
}
|
|
795
834
|
}
|
|
796
835
|
}
|
|
@@ -799,10 +838,7 @@ export class ExtensionRunner {
|
|
|
799
838
|
async emitContext(messages) {
|
|
800
839
|
const ctx = this.createContext();
|
|
801
840
|
let currentMessages = structuredClone(messages);
|
|
802
|
-
for (const ext of this.extensions) {
|
|
803
|
-
const handlers = ext.handlers.get("context");
|
|
804
|
-
if (!handlers || handlers.length === 0)
|
|
805
|
-
continue;
|
|
841
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "context")) {
|
|
806
842
|
for (const handler of handlers) {
|
|
807
843
|
try {
|
|
808
844
|
const event = { type: "context", messages: currentMessages };
|
|
@@ -828,10 +864,7 @@ export class ExtensionRunner {
|
|
|
828
864
|
async emitBeforeProviderRequest(payload) {
|
|
829
865
|
const ctx = this.createContext();
|
|
830
866
|
let currentPayload = payload;
|
|
831
|
-
for (const ext of this.extensions) {
|
|
832
|
-
const handlers = ext.handlers.get("before_provider_request");
|
|
833
|
-
if (!handlers || handlers.length === 0)
|
|
834
|
-
continue;
|
|
867
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "before_provider_request")) {
|
|
835
868
|
for (const handler of handlers) {
|
|
836
869
|
try {
|
|
837
870
|
const event = {
|
|
@@ -859,10 +892,7 @@ export class ExtensionRunner {
|
|
|
859
892
|
}
|
|
860
893
|
async emitBeforeProviderHeaders(headers) {
|
|
861
894
|
const ctx = this.createContext();
|
|
862
|
-
for (const ext of this.extensions) {
|
|
863
|
-
const handlers = ext.handlers.get("before_provider_headers");
|
|
864
|
-
if (!handlers || handlers.length === 0)
|
|
865
|
-
continue;
|
|
895
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "before_provider_headers")) {
|
|
866
896
|
for (const handler of handlers) {
|
|
867
897
|
try {
|
|
868
898
|
// Handlers mutate `headers` in place; the return value is ignored.
|
|
@@ -886,37 +916,34 @@ export class ExtensionRunner {
|
|
|
886
916
|
}
|
|
887
917
|
return headers;
|
|
888
918
|
}
|
|
889
|
-
async emitBeforeAgentStart(prompt, images,
|
|
890
|
-
|
|
919
|
+
async emitBeforeAgentStart(prompt, images, systemPromptOptions) {
|
|
920
|
+
const currentOptions = normalizeBuildSystemPromptOptions(systemPromptOptions);
|
|
921
|
+
const renderCurrentSystemPrompt = () => buildSystemPrompt(currentOptions);
|
|
891
922
|
const ctx = Object.defineProperties({}, Object.getOwnPropertyDescriptors(this.createContext()));
|
|
892
923
|
ctx.getSystemPrompt = () => {
|
|
893
924
|
this.assertActive();
|
|
894
|
-
return
|
|
925
|
+
return renderCurrentSystemPrompt();
|
|
895
926
|
};
|
|
896
927
|
const messages = [];
|
|
897
|
-
|
|
898
|
-
for (const ext of this.extensions) {
|
|
899
|
-
const handlers = ext.handlers.get("before_agent_start");
|
|
900
|
-
if (!handlers || handlers.length === 0)
|
|
901
|
-
continue;
|
|
928
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "before_agent_start")) {
|
|
902
929
|
for (const handler of handlers) {
|
|
903
930
|
try {
|
|
904
931
|
const event = {
|
|
905
932
|
type: "before_agent_start",
|
|
906
933
|
prompt,
|
|
907
934
|
images,
|
|
908
|
-
systemPrompt
|
|
909
|
-
|
|
935
|
+
get systemPrompt() {
|
|
936
|
+
return renderCurrentSystemPrompt();
|
|
937
|
+
},
|
|
938
|
+
systemPromptOptions: currentOptions,
|
|
910
939
|
};
|
|
911
940
|
const handlerResult = await handler(event, ctx);
|
|
912
941
|
if (handlerResult) {
|
|
913
942
|
const result = handlerResult;
|
|
914
|
-
if (result.message)
|
|
943
|
+
if (result.message)
|
|
915
944
|
messages.push(result.message);
|
|
916
|
-
}
|
|
917
945
|
if (result.systemPrompt !== undefined) {
|
|
918
|
-
|
|
919
|
-
systemPromptModified = true;
|
|
946
|
+
currentOptions.forceSystemPrompt = result.systemPrompt;
|
|
920
947
|
}
|
|
921
948
|
}
|
|
922
949
|
}
|
|
@@ -932,23 +959,14 @@ export class ExtensionRunner {
|
|
|
932
959
|
}
|
|
933
960
|
}
|
|
934
961
|
}
|
|
935
|
-
|
|
936
|
-
return {
|
|
937
|
-
messages: messages.length > 0 ? messages : undefined,
|
|
938
|
-
systemPrompt: systemPromptModified ? currentSystemPrompt : undefined,
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
return undefined;
|
|
962
|
+
return { messages, systemPromptOptions: currentOptions };
|
|
942
963
|
}
|
|
943
964
|
async emitResourcesDiscover(cwd, reason) {
|
|
944
965
|
const ctx = this.createContext();
|
|
945
966
|
const skillPaths = [];
|
|
946
967
|
const promptPaths = [];
|
|
947
968
|
const themePaths = [];
|
|
948
|
-
for (const ext of this.extensions) {
|
|
949
|
-
const handlers = ext.handlers.get("resources_discover");
|
|
950
|
-
if (!handlers || handlers.length === 0)
|
|
951
|
-
continue;
|
|
969
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "resources_discover")) {
|
|
952
970
|
for (const handler of handlers) {
|
|
953
971
|
try {
|
|
954
972
|
const event = { type: "resources_discover", cwd, reason };
|
|
@@ -983,8 +1001,8 @@ export class ExtensionRunner {
|
|
|
983
1001
|
const ctx = this.createContext();
|
|
984
1002
|
let currentText = text;
|
|
985
1003
|
let currentImages = images;
|
|
986
|
-
for (const ext of this.extensions) {
|
|
987
|
-
for (const handler of
|
|
1004
|
+
for (const { ext, handlers } of snapshotEventHandlers(this.extensions, "input")) {
|
|
1005
|
+
for (const handler of handlers) {
|
|
988
1006
|
try {
|
|
989
1007
|
const event = {
|
|
990
1008
|
type: "input",
|