@selesai/code 0.9.5 → 0.9.8
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 +18 -0
- package/dist/cli/credential-print.js +4 -4
- package/dist/cli.js +0 -0
- package/dist/core/agent-session-runtime.js +1 -4
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.js +26 -0
- package/dist/core/compaction/branch-summarization.js +30 -30
- package/dist/core/compaction/compaction.js +81 -81
- package/dist/core/compaction/utils.js +2 -2
- package/dist/core/export-html/template.css +1066 -1066
- package/dist/core/export-html/template.html +55 -55
- package/dist/core/export-html/template.js +1864 -1864
- package/dist/core/export-html/vendor/highlight.min.js +1212 -1212
- package/dist/core/export-html/vendor/marked.min.js +78 -78
- package/dist/core/handoff.d.ts +11 -0
- package/dist/core/handoff.js +49 -0
- package/dist/core/messages.js +7 -7
- package/dist/extensions/context-compaction-reminder.test.ts +82 -82
- package/dist/extensions/context-compaction-reminder.ts +28 -28
- package/dist/extensions/handoff-new.ts +14 -75
- package/dist/extensions/pi-intercom/LICENSE +21 -21
- package/dist/extensions/pi-intercom/broker/client.test.ts +83 -83
- package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -387
- package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -114
- package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -153
- package/dist/extensions/pi-intercom/broker/paths.ts +134 -134
- package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -34
- package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -21
- package/dist/extensions/pi-intercom/cwd.test.ts +40 -40
- package/dist/extensions/pi-intercom/cwd.ts +31 -31
- package/dist/extensions/pi-intercom/extension-api.ts +44 -44
- package/dist/extensions/pi-intercom/format-context.test.ts +31 -31
- package/dist/extensions/pi-intercom/format-context.ts +32 -32
- package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -66
- package/dist/extensions/pi-intercom/ui/compose.ts +143 -143
- package/dist/extensions/pi-intercom/ui/session-list.ts +166 -166
- package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +286 -286
- package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +108 -108
- package/dist/extensions/pi-powerline-footer/separators.ts +57 -57
- package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +47 -47
- package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +39 -39
- package/dist/extensions/pi-powerline-footer/theme.example.json +24 -24
- package/dist/extensions/pi-powerline-footer/theme.json +12 -12
- package/dist/extensions/pi-powerline-footer/tps.ts +345 -345
- package/dist/extensions/pi-rewind-hook/README.md +245 -245
- package/dist/extensions/pi-rewind-hook/index.ts +1445 -1445
- package/dist/extensions/pi-rewind-hook/package.json +29 -29
- package/dist/extensions/pi-subagents/install.mjs +0 -0
- package/dist/extensions/pi-web-agent/package.json +31 -31
- package/dist/extensions/pi-web-agent/src/backends/config.ts +205 -205
- package/dist/extensions/pi-web-agent/src/backends/doctor.ts +136 -136
- package/dist/extensions/pi-web-agent/src/backends/factory.ts +152 -152
- package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +25 -25
- package/dist/extensions/pi-web-agent/src/cache/ttl-cache.ts +28 -28
- package/dist/extensions/pi-web-agent/src/changelog-notice.ts +136 -136
- package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +946 -946
- package/dist/extensions/pi-web-agent/src/extension.ts +126 -126
- package/dist/extensions/pi-web-agent/src/extract/readability.ts +118 -118
- package/dist/extensions/pi-web-agent/src/fetch/browser-resolution.ts +199 -199
- package/dist/extensions/pi-web-agent/src/fetch/firecrawl-fetch.ts +100 -100
- package/dist/extensions/pi-web-agent/src/fetch/headless-fetch.ts +117 -117
- package/dist/extensions/pi-web-agent/src/fetch/http-fetch.ts +67 -67
- package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +60 -60
- package/dist/extensions/pi-web-agent/src/orchestration/candidate-selector.ts +50 -50
- package/dist/extensions/pi-web-agent/src/orchestration/direct-url.ts +52 -52
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-quality.ts +105 -105
- package/dist/extensions/pi-web-agent/src/orchestration/evidence-ranker.ts +45 -45
- package/dist/extensions/pi-web-agent/src/orchestration/index.ts +28 -28
- package/dist/extensions/pi-web-agent/src/orchestration/query-planner.ts +47 -47
- package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +376 -376
- package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +64 -64
- package/dist/extensions/pi-web-agent/src/orchestration/research-worker.ts +181 -181
- package/dist/extensions/pi-web-agent/src/orchestration/source-profile.ts +101 -101
- package/dist/extensions/pi-web-agent/src/orchestration/stop-decider.ts +81 -81
- package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +210 -210
- package/dist/extensions/pi-web-agent/src/presentation/config.ts +75 -75
- package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +61 -61
- package/dist/extensions/pi-web-agent/src/presentation/fetch-presentation.ts +54 -54
- package/dist/extensions/pi-web-agent/src/presentation/search-presentation.ts +41 -41
- package/dist/extensions/pi-web-agent/src/presentation/select-view.ts +20 -20
- package/dist/extensions/pi-web-agent/src/presentation/types.ts +63 -63
- package/dist/extensions/pi-web-agent/src/search/brave.ts +114 -114
- package/dist/extensions/pi-web-agent/src/search/duckduckgo.ts +72 -72
- package/dist/extensions/pi-web-agent/src/search/searxng.ts +96 -96
- package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +71 -71
- package/dist/extensions/pi-web-agent/src/tools/web-fetch-headless.ts +31 -31
- package/dist/extensions/pi-web-agent/src/tools/web-fetch.ts +31 -31
- package/dist/extensions/pi-web-agent/src/tools/web-search.ts +157 -157
- package/dist/extensions/pi-web-agent/src/types.ts +88 -88
- package/dist/extensions/ponytail/package.json +8 -8
- package/dist/extensions/question/batch.ts +103 -103
- package/dist/extensions/question/constants.ts +30 -30
- package/dist/extensions/question/helpers.ts +58 -58
- package/dist/extensions/question/navigation.ts +14 -14
- package/dist/extensions/question/package.json +19 -19
- package/dist/extensions/question/schemas.ts +43 -43
- package/dist/extensions/question/selection-mode.ts +46 -46
- package/dist/extensions/question/shortcuts.ts +44 -44
- package/dist/extensions/question/types.ts +132 -132
- package/dist/extensions/test-resolve-hook-impl.mjs +6 -6
- package/dist/extensions/test-resolve-hook.mjs +6 -6
- package/dist/extensions/web-agent-onboarding.ts +222 -222
- package/dist/extensions/workflow/package.json +17 -17
- package/dist/modes/interactive/components/model-selector.d.ts +1 -0
- package/dist/modes/interactive/components/model-selector.js +8 -4
- package/dist/modes/interactive/interactive-mode.js +9 -5
- package/dist/modes/rpc/rpc-mode.js +24 -0
- package/dist/modes/rpc/rpc-types.d.ts +19 -0
- package/dist/package-manager-cli.js +71 -71
- package/dist/rpc-entry.js +0 -0
- package/dist/skills/agent-browser/SKILL.md +52 -52
- package/dist/skills/batch-grill-me/SKILL.md +19 -19
- package/dist/skills/grill-me/SKILL.md +10 -10
- package/dist/skills/handoff/SKILL.md +16 -16
- package/dist/skills/handoff-text/SKILL.md +14 -14
- package/dist/skills/implanger/SKILL.md +69 -69
- package/dist/skills/improve-codebase/REFERENCE.md +78 -78
- package/dist/skills/improve-codebase/SKILL.md +178 -178
- package/dist/skills/planger/SKILL.md +166 -166
- package/dist/skills/ponytail/SKILL.md +116 -116
- package/dist/skills/ponytail-audit/SKILL.md +42 -42
- package/dist/skills/ponytail-debt/SKILL.md +45 -45
- package/dist/skills/ponytail-gain/SKILL.md +51 -51
- package/dist/skills/ponytail-help/SKILL.md +70 -70
- package/dist/skills/ponytail-review/SKILL.md +58 -58
- package/dist/skills/selesai-handoff/SKILL.md +20 -20
- package/dist/skills/workflow-creation/SKILL.md +73 -73
- package/dist/themes/powerline-footer/theme.json +33 -33
- package/docs/compaction.md +396 -396
- package/docs/containerization.md +111 -111
- package/docs/development.md +71 -71
- package/docs/docs.json +164 -164
- package/docs/environment-variables.md +86 -86
- package/docs/index.md +83 -83
- package/docs/json.md +82 -82
- package/docs/models.md +502 -502
- package/docs/packages.md +227 -227
- package/docs/plans/subagent-delegation/phase-0-correctness.md +264 -264
- package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +485 -485
- package/docs/plans/subagent-delegation/phase-2-context-controls.md +281 -281
- package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +361 -361
- package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +380 -380
- package/docs/prompt-templates.md +95 -95
- package/docs/providers.md +293 -293
- package/docs/sdk.md +1143 -1143
- package/docs/security.md +59 -59
- package/docs/session-format.md +414 -414
- package/docs/sessions.md +145 -145
- package/docs/shared-host-extensions.md +109 -109
- package/docs/shell-aliases.md +13 -13
- package/docs/skills.md +231 -231
- package/docs/terminal-setup.md +142 -142
- package/docs/termux.md +127 -127
- package/docs/themes.md +295 -295
- package/docs/tmux.md +63 -63
- package/docs/tui.md +927 -927
- package/docs/windows.md +17 -17
- package/examples/README.md +25 -25
- package/examples/extensions/README.md +211 -211
- package/examples/extensions/auto-commit-on-exit.ts +49 -49
- package/examples/extensions/bash-spawn-hook.ts +30 -30
- package/examples/extensions/bookmark.ts +50 -50
- package/examples/extensions/border-status-editor.ts +150 -150
- package/examples/extensions/built-in-tool-renderer.ts +249 -249
- package/examples/extensions/claude-rules.ts +86 -86
- package/examples/extensions/commands.ts +72 -72
- package/examples/extensions/confirm-destructive.ts +59 -59
- package/examples/extensions/custom-compaction.ts +130 -130
- package/examples/extensions/custom-footer.ts +64 -64
- package/examples/extensions/custom-header.ts +73 -73
- package/examples/extensions/custom-provider-anthropic/index.ts +610 -610
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -24
- package/examples/extensions/custom-provider-anthropic/package.json +19 -19
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +404 -404
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -16
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -82
- package/examples/extensions/dirty-repo-guard.ts +56 -56
- package/examples/extensions/doom-overlay/README.md +46 -46
- package/examples/extensions/doom-overlay/doom/build/doom.js +21 -21
- package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
- package/examples/extensions/doom-overlay/doom/build.sh +152 -152
- package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -72
- package/examples/extensions/doom-overlay/doom-component.ts +132 -132
- package/examples/extensions/doom-overlay/doom-engine.ts +173 -173
- package/examples/extensions/doom-overlay/doom-keys.ts +104 -104
- package/examples/extensions/doom-overlay/index.ts +74 -74
- package/examples/extensions/doom-overlay/wad-finder.ts +51 -51
- package/examples/extensions/dynamic-resources/SKILL.md +8 -8
- package/examples/extensions/dynamic-resources/dynamic.json +79 -79
- package/examples/extensions/dynamic-resources/dynamic.md +5 -5
- package/examples/extensions/dynamic-resources/index.ts +15 -15
- package/examples/extensions/dynamic-tools.ts +74 -74
- package/examples/extensions/event-bus.ts +43 -43
- package/examples/extensions/file-trigger.ts +41 -41
- package/examples/extensions/git-checkpoint.ts +53 -53
- package/examples/extensions/git-merge-and-resolve.ts +115 -115
- package/examples/extensions/github-issue-autocomplete.ts +185 -185
- package/examples/extensions/gondolin/index.ts +531 -531
- package/examples/extensions/gondolin/package-lock.json +185 -185
- package/examples/extensions/gondolin/package.json +19 -19
- package/examples/extensions/handoff.ts +199 -199
- package/examples/extensions/hello.ts +26 -26
- package/examples/extensions/hidden-thinking-label.ts +53 -53
- package/examples/extensions/inline-bash.ts +94 -94
- package/examples/extensions/input-transform-streaming.ts +39 -39
- package/examples/extensions/input-transform.ts +43 -43
- package/examples/extensions/interactive-shell.ts +196 -196
- package/examples/extensions/mac-system-theme.ts +47 -47
- package/examples/extensions/message-renderer.ts +59 -59
- package/examples/extensions/minimal-mode.ts +426 -426
- package/examples/extensions/modal-editor.ts +85 -85
- package/examples/extensions/model-status.ts +31 -31
- package/examples/extensions/notify.ts +55 -55
- package/examples/extensions/overlay-qa-tests.ts +1450 -1450
- package/examples/extensions/overlay-test.ts +153 -153
- package/examples/extensions/permission-gate.ts +34 -34
- package/examples/extensions/pirate.ts +47 -47
- package/examples/extensions/plan-mode/README.md +66 -66
- package/examples/extensions/plan-mode/index.ts +390 -390
- package/examples/extensions/plan-mode/utils.ts +168 -168
- package/examples/extensions/preset.ts +436 -436
- package/examples/extensions/project-trust.ts +64 -64
- package/examples/extensions/prompt-customizer.ts +97 -97
- package/examples/extensions/protected-paths.ts +30 -30
- package/examples/extensions/provider-payload.ts +18 -18
- package/examples/extensions/qna.ts +122 -122
- package/examples/extensions/question.ts +285 -285
- package/examples/extensions/questionnaire.ts +448 -448
- package/examples/extensions/rainbow-editor.ts +88 -88
- package/examples/extensions/reload-runtime.ts +37 -37
- package/examples/extensions/rpc-demo.ts +118 -118
- package/examples/extensions/sandbox/index.ts +321 -321
- package/examples/extensions/sandbox/package-lock.json +92 -92
- package/examples/extensions/sandbox/package.json +19 -19
- package/examples/extensions/send-user-message.ts +97 -97
- package/examples/extensions/session-name.ts +27 -27
- package/examples/extensions/shutdown-command.ts +63 -63
- package/examples/extensions/snake.ts +343 -343
- package/examples/extensions/space-invaders.ts +560 -560
- package/examples/extensions/ssh.ts +220 -220
- package/examples/extensions/status-line.ts +32 -32
- package/examples/extensions/structured-output.ts +65 -65
- package/examples/extensions/subagent/README.md +175 -175
- package/examples/extensions/subagent/agents/planner.md +37 -37
- package/examples/extensions/subagent/agents/reviewer.md +35 -35
- package/examples/extensions/subagent/agents/scout.md +50 -50
- package/examples/extensions/subagent/agents/worker.md +24 -24
- package/examples/extensions/subagent/agents.ts +126 -126
- package/examples/extensions/subagent/index.ts +1015 -1015
- package/examples/extensions/subagent/prompts/implement-and-review.md +10 -10
- package/examples/extensions/subagent/prompts/implement.md +10 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -9
- package/examples/extensions/summarize.ts +209 -209
- package/examples/extensions/system-prompt-header.ts +17 -17
- package/examples/extensions/tic-tac-toe.ts +1008 -1008
- package/examples/extensions/timed-confirm.ts +70 -70
- package/examples/extensions/titlebar-spinner.ts +58 -58
- package/examples/extensions/todo.ts +297 -297
- package/examples/extensions/tool-override.ts +144 -144
- package/examples/extensions/tools.ts +146 -146
- package/examples/extensions/trigger-compact.ts +50 -50
- package/examples/extensions/truncated-tool.ts +195 -195
- package/examples/extensions/widget-placement.ts +9 -9
- package/examples/extensions/with-deps/index.ts +32 -32
- package/examples/extensions/with-deps/package-lock.json +31 -31
- package/examples/extensions/with-deps/package.json +22 -22
- package/examples/extensions/working-indicator.ts +123 -123
- package/examples/extensions/working-message-test.ts +25 -25
- package/examples/rpc-extension-ui.ts +632 -632
- package/examples/sdk/01-minimal.ts +26 -26
- package/examples/sdk/02-custom-model.ts +53 -53
- package/examples/sdk/03-custom-prompt.ts +75 -75
- package/examples/sdk/04-skills.ts +55 -55
- package/examples/sdk/05-tools.ts +48 -48
- package/examples/sdk/06-extensions.ts +99 -99
- package/examples/sdk/07-context-files.ts +47 -47
- package/examples/sdk/08-prompt-templates.ts +51 -51
- package/examples/sdk/09-api-keys-and-oauth.ts +52 -52
- package/examples/sdk/10-settings.ts +53 -53
- package/examples/sdk/11-sessions.ts +52 -52
- package/examples/sdk/12-full-control.ts +79 -79
- package/examples/sdk/13-session-runtime.ts +67 -67
- package/examples/sdk/README.md +144 -144
- package/package.json +1 -1
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
import type { ExtensionAPI } from '@selesai/code';
|
|
2
|
-
import { DEFAULT_BACKEND_CONFIG, type BackendConfig } from './backends/config.js';
|
|
3
|
-
import { Type } from 'typebox';
|
|
4
|
-
import { registerWebAgentConfigCommands } from './commands/web-agent-config.js';
|
|
5
|
-
import { DEFAULT_PRESENTATION_CONFIG, resolvePresentationMode } from './presentation/config.js';
|
|
6
|
-
import { createResearchWorkflow } from './orchestration/index.js';
|
|
7
|
-
import { loadPresentationConfigLayers } from './presentation/config-store.js';
|
|
8
|
-
import { selectPresentationView } from './presentation/select-view.js';
|
|
9
|
-
import type {
|
|
10
|
-
PresentationConfig,
|
|
11
|
-
PresentationEnvelope,
|
|
12
|
-
PresentationToolName
|
|
13
|
-
} from './presentation/types.js';
|
|
14
|
-
import { createWebExploreTool } from './tools/web-explore.js';
|
|
15
|
-
import type { WebExploreResponse } from './types.js';
|
|
16
|
-
import { getUpdateChangelogNotice } from './changelog-notice.js';
|
|
17
|
-
|
|
18
|
-
type ToolResultWithPresentation = {
|
|
19
|
-
presentation?: PresentationEnvelope;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
async function loadWebAgentConfig(pi: ExtensionAPI) {
|
|
23
|
-
const store = (
|
|
24
|
-
pi as ExtensionAPI & {
|
|
25
|
-
__presentationConfigStore?: {
|
|
26
|
-
load?: typeof loadPresentationConfigLayers;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
).__presentationConfigStore;
|
|
30
|
-
|
|
31
|
-
return store?.load?.() ?? loadPresentationConfigLayers();
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function getEffectivePresentationConfig(pi: ExtensionAPI): Promise<PresentationConfig> {
|
|
35
|
-
try {
|
|
36
|
-
const loaded = await loadWebAgentConfig(pi);
|
|
37
|
-
return loaded.effectiveConfig;
|
|
38
|
-
} catch {
|
|
39
|
-
return DEFAULT_PRESENTATION_CONFIG;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function getEffectiveBackendConfig(pi: ExtensionAPI): Promise<BackendConfig> {
|
|
44
|
-
try {
|
|
45
|
-
const loaded = await loadWebAgentConfig(pi);
|
|
46
|
-
return loaded.effectiveBackends ?? DEFAULT_BACKEND_CONFIG;
|
|
47
|
-
} catch {
|
|
48
|
-
return DEFAULT_BACKEND_CONFIG;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async function renderToolText(
|
|
53
|
-
pi: ExtensionAPI,
|
|
54
|
-
toolName: PresentationToolName,
|
|
55
|
-
details: ToolResultWithPresentation
|
|
56
|
-
): Promise<string> {
|
|
57
|
-
const config = await getEffectivePresentationConfig(pi);
|
|
58
|
-
const mode = resolvePresentationMode(toolName, config);
|
|
59
|
-
return selectPresentationView(details.presentation, mode) ?? JSON.stringify(details, null, 2);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export default function extension(pi: ExtensionAPI) {
|
|
63
|
-
registerWebAgentConfigCommands(pi);
|
|
64
|
-
|
|
65
|
-
const injectedWebExplore = (pi as ExtensionAPI & { __webExploreTool?: ReturnType<typeof createWebExploreTool> }).__webExploreTool;
|
|
66
|
-
let cachedBackendKey: string | undefined;
|
|
67
|
-
let cachedWebExplore: ReturnType<typeof createWebExploreTool> | undefined;
|
|
68
|
-
|
|
69
|
-
async function getConfiguredWebExplore() {
|
|
70
|
-
if (injectedWebExplore) return injectedWebExplore;
|
|
71
|
-
|
|
72
|
-
const backendConfig = await getEffectiveBackendConfig(pi);
|
|
73
|
-
const backendKey = JSON.stringify(backendConfig);
|
|
74
|
-
if (!cachedWebExplore || cachedBackendKey !== backendKey) {
|
|
75
|
-
cachedBackendKey = backendKey;
|
|
76
|
-
cachedWebExplore = createWebExploreTool({
|
|
77
|
-
explore: createResearchWorkflow({ backendConfig })
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return cachedWebExplore;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
pi.on('session_start', async (_event, ctx) => {
|
|
85
|
-
try {
|
|
86
|
-
const notice = await getUpdateChangelogNotice();
|
|
87
|
-
if (notice) {
|
|
88
|
-
ctx.ui.notify(`pi-web-agent updated\n\n${notice}`, 'info');
|
|
89
|
-
}
|
|
90
|
-
} catch {
|
|
91
|
-
// Never block extension startup on changelog display.
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
pi.on('before_agent_start', async (event) => ({
|
|
96
|
-
systemPrompt:
|
|
97
|
-
`${event.systemPrompt}\n\n` +
|
|
98
|
-
'For web research questions that require finding and comparing sources, use web_explore. ' +
|
|
99
|
-
'web_explore handles search, fetch, source ranking, and headless escalation internally. ' +
|
|
100
|
-
'If more web evidence is needed after web_explore, call web_explore again with a narrower query; do not use shell/network commands such as curl, Invoke-WebRequest, npm view/search/pack, or direct HTTP URLs for web research.'
|
|
101
|
-
}));
|
|
102
|
-
|
|
103
|
-
pi.registerTool({
|
|
104
|
-
name: 'web_explore',
|
|
105
|
-
label: 'Web Explore',
|
|
106
|
-
description:
|
|
107
|
-
'Research a web question using bounded search/fetch passes, source ranking, and targeted headless escalation. Use this for web research, current docs/discussion lookups, and recommendation summaries.',
|
|
108
|
-
parameters: Type.Object({
|
|
109
|
-
query: Type.String({ description: 'Web research question to explore.' })
|
|
110
|
-
}),
|
|
111
|
-
async execute(_toolCallId, params) {
|
|
112
|
-
const webExplore = await getConfiguredWebExplore();
|
|
113
|
-
const result: WebExploreResponse = await webExplore({ query: params.query });
|
|
114
|
-
return {
|
|
115
|
-
content: [
|
|
116
|
-
{
|
|
117
|
-
type: 'text',
|
|
118
|
-
text: await renderToolText(pi, 'web_explore', result)
|
|
119
|
-
}
|
|
120
|
-
],
|
|
121
|
-
details: result,
|
|
122
|
-
isError: result.status === 'error'
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
1
|
+
import type { ExtensionAPI } from '@selesai/code';
|
|
2
|
+
import { DEFAULT_BACKEND_CONFIG, type BackendConfig } from './backends/config.js';
|
|
3
|
+
import { Type } from 'typebox';
|
|
4
|
+
import { registerWebAgentConfigCommands } from './commands/web-agent-config.js';
|
|
5
|
+
import { DEFAULT_PRESENTATION_CONFIG, resolvePresentationMode } from './presentation/config.js';
|
|
6
|
+
import { createResearchWorkflow } from './orchestration/index.js';
|
|
7
|
+
import { loadPresentationConfigLayers } from './presentation/config-store.js';
|
|
8
|
+
import { selectPresentationView } from './presentation/select-view.js';
|
|
9
|
+
import type {
|
|
10
|
+
PresentationConfig,
|
|
11
|
+
PresentationEnvelope,
|
|
12
|
+
PresentationToolName
|
|
13
|
+
} from './presentation/types.js';
|
|
14
|
+
import { createWebExploreTool } from './tools/web-explore.js';
|
|
15
|
+
import type { WebExploreResponse } from './types.js';
|
|
16
|
+
import { getUpdateChangelogNotice } from './changelog-notice.js';
|
|
17
|
+
|
|
18
|
+
type ToolResultWithPresentation = {
|
|
19
|
+
presentation?: PresentationEnvelope;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
async function loadWebAgentConfig(pi: ExtensionAPI) {
|
|
23
|
+
const store = (
|
|
24
|
+
pi as ExtensionAPI & {
|
|
25
|
+
__presentationConfigStore?: {
|
|
26
|
+
load?: typeof loadPresentationConfigLayers;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
).__presentationConfigStore;
|
|
30
|
+
|
|
31
|
+
return store?.load?.() ?? loadPresentationConfigLayers();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function getEffectivePresentationConfig(pi: ExtensionAPI): Promise<PresentationConfig> {
|
|
35
|
+
try {
|
|
36
|
+
const loaded = await loadWebAgentConfig(pi);
|
|
37
|
+
return loaded.effectiveConfig;
|
|
38
|
+
} catch {
|
|
39
|
+
return DEFAULT_PRESENTATION_CONFIG;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function getEffectiveBackendConfig(pi: ExtensionAPI): Promise<BackendConfig> {
|
|
44
|
+
try {
|
|
45
|
+
const loaded = await loadWebAgentConfig(pi);
|
|
46
|
+
return loaded.effectiveBackends ?? DEFAULT_BACKEND_CONFIG;
|
|
47
|
+
} catch {
|
|
48
|
+
return DEFAULT_BACKEND_CONFIG;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function renderToolText(
|
|
53
|
+
pi: ExtensionAPI,
|
|
54
|
+
toolName: PresentationToolName,
|
|
55
|
+
details: ToolResultWithPresentation
|
|
56
|
+
): Promise<string> {
|
|
57
|
+
const config = await getEffectivePresentationConfig(pi);
|
|
58
|
+
const mode = resolvePresentationMode(toolName, config);
|
|
59
|
+
return selectPresentationView(details.presentation, mode) ?? JSON.stringify(details, null, 2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default function extension(pi: ExtensionAPI) {
|
|
63
|
+
registerWebAgentConfigCommands(pi);
|
|
64
|
+
|
|
65
|
+
const injectedWebExplore = (pi as ExtensionAPI & { __webExploreTool?: ReturnType<typeof createWebExploreTool> }).__webExploreTool;
|
|
66
|
+
let cachedBackendKey: string | undefined;
|
|
67
|
+
let cachedWebExplore: ReturnType<typeof createWebExploreTool> | undefined;
|
|
68
|
+
|
|
69
|
+
async function getConfiguredWebExplore() {
|
|
70
|
+
if (injectedWebExplore) return injectedWebExplore;
|
|
71
|
+
|
|
72
|
+
const backendConfig = await getEffectiveBackendConfig(pi);
|
|
73
|
+
const backendKey = JSON.stringify(backendConfig);
|
|
74
|
+
if (!cachedWebExplore || cachedBackendKey !== backendKey) {
|
|
75
|
+
cachedBackendKey = backendKey;
|
|
76
|
+
cachedWebExplore = createWebExploreTool({
|
|
77
|
+
explore: createResearchWorkflow({ backendConfig })
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return cachedWebExplore;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pi.on('session_start', async (_event, ctx) => {
|
|
85
|
+
try {
|
|
86
|
+
const notice = await getUpdateChangelogNotice();
|
|
87
|
+
if (notice) {
|
|
88
|
+
ctx.ui.notify(`pi-web-agent updated\n\n${notice}`, 'info');
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Never block extension startup on changelog display.
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
pi.on('before_agent_start', async (event) => ({
|
|
96
|
+
systemPrompt:
|
|
97
|
+
`${event.systemPrompt}\n\n` +
|
|
98
|
+
'For web research questions that require finding and comparing sources, use web_explore. ' +
|
|
99
|
+
'web_explore handles search, fetch, source ranking, and headless escalation internally. ' +
|
|
100
|
+
'If more web evidence is needed after web_explore, call web_explore again with a narrower query; do not use shell/network commands such as curl, Invoke-WebRequest, npm view/search/pack, or direct HTTP URLs for web research.'
|
|
101
|
+
}));
|
|
102
|
+
|
|
103
|
+
pi.registerTool({
|
|
104
|
+
name: 'web_explore',
|
|
105
|
+
label: 'Web Explore',
|
|
106
|
+
description:
|
|
107
|
+
'Research a web question using bounded search/fetch passes, source ranking, and targeted headless escalation. Use this for web research, current docs/discussion lookups, and recommendation summaries.',
|
|
108
|
+
parameters: Type.Object({
|
|
109
|
+
query: Type.String({ description: 'Web research question to explore.' })
|
|
110
|
+
}),
|
|
111
|
+
async execute(_toolCallId, params) {
|
|
112
|
+
const webExplore = await getConfiguredWebExplore();
|
|
113
|
+
const result: WebExploreResponse = await webExplore({ query: params.query });
|
|
114
|
+
return {
|
|
115
|
+
content: [
|
|
116
|
+
{
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: await renderToolText(pi, 'web_explore', result)
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
details: result,
|
|
122
|
+
isError: result.status === 'error'
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
import { Readability } from '@mozilla/readability';
|
|
2
|
-
import { JSDOM, VirtualConsole } from 'jsdom';
|
|
3
|
-
import type { ExtractedContent } from '../types.js';
|
|
4
|
-
|
|
5
|
-
export type ReadableExtractionMode = 'readability' | 'fallback';
|
|
6
|
-
|
|
7
|
-
export type SafeReadableExtraction = {
|
|
8
|
-
mode: ReadableExtractionMode;
|
|
9
|
-
content: ExtractedContent;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export function extractReadableContent(html: string, maxLength = 4000): ExtractedContent {
|
|
13
|
-
let stylesheetError: Error | undefined;
|
|
14
|
-
const virtualConsole = new VirtualConsole();
|
|
15
|
-
|
|
16
|
-
virtualConsole.on('jsdomError', (error) => {
|
|
17
|
-
if (!stylesheetError && error.message.includes('Could not parse CSS stylesheet')) {
|
|
18
|
-
stylesheetError = error;
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const dom = new JSDOM(html, {
|
|
23
|
-
url: 'https://example.com',
|
|
24
|
-
virtualConsole
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (stylesheetError) {
|
|
28
|
-
throw stylesheetError;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const article = new Readability(dom.window.document).parse();
|
|
32
|
-
const rawText = (article?.textContent ?? dom.window.document.body.textContent ?? '').trim();
|
|
33
|
-
const text = rawText.slice(0, maxLength);
|
|
34
|
-
|
|
35
|
-
const fallbackTitle = dom.window.document.title || undefined;
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
title: article?.title ?? fallbackTitle,
|
|
39
|
-
byline: article?.byline || undefined,
|
|
40
|
-
text
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function decodeHtmlEntities(text: string): string {
|
|
45
|
-
return text
|
|
46
|
-
.replace(/ /gi, ' ')
|
|
47
|
-
.replace(/&/gi, '&')
|
|
48
|
-
.replace(/</gi, '<')
|
|
49
|
-
.replace(/>/gi, '>')
|
|
50
|
-
.replace(/"/gi, '"')
|
|
51
|
-
.replace(/'/gi, "'")
|
|
52
|
-
.replace(/'/gi, "'")
|
|
53
|
-
.replace(///gi, '/')
|
|
54
|
-
.replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code)))
|
|
55
|
-
.replace(/&#x([\da-f]+);/gi, (_, code) => String.fromCharCode(parseInt(code, 16)));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function extractTitle(html: string): string | undefined {
|
|
59
|
-
const match = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
60
|
-
if (!match) return undefined;
|
|
61
|
-
return decodeHtmlEntities(match[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()) || undefined;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function stripTagContent(html: string, tagName: string): string {
|
|
65
|
-
return html.replace(new RegExp(`<${tagName}\\b[^>]*>[\\s\\S]*?<\\/${tagName}>`, 'gi'), ' ');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function extractPreferredSection(html: string): string {
|
|
69
|
-
const mainMatch = html.match(/<main\b[^>]*>([\s\S]*?)<\/main>/i);
|
|
70
|
-
if (mainMatch) return mainMatch[1];
|
|
71
|
-
|
|
72
|
-
const articleMatch = html.match(/<article\b[^>]*>([\s\S]*?)<\/article>/i);
|
|
73
|
-
if (articleMatch) return articleMatch[1];
|
|
74
|
-
|
|
75
|
-
const bodyMatch = html.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
|
|
76
|
-
if (bodyMatch) return bodyMatch[1];
|
|
77
|
-
|
|
78
|
-
return html;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function extractFallbackText(html: string, maxLength: number): ExtractedContent {
|
|
82
|
-
const title = extractTitle(html);
|
|
83
|
-
let section = extractPreferredSection(html);
|
|
84
|
-
|
|
85
|
-
section = stripTagContent(section, 'script');
|
|
86
|
-
section = stripTagContent(section, 'style');
|
|
87
|
-
section = stripTagContent(section, 'noscript');
|
|
88
|
-
section = stripTagContent(section, 'svg');
|
|
89
|
-
section = stripTagContent(section, 'template');
|
|
90
|
-
|
|
91
|
-
const text = decodeHtmlEntities(section)
|
|
92
|
-
.replace(/<[^>]+>/g, ' ')
|
|
93
|
-
.replace(/\s+/g, ' ')
|
|
94
|
-
.trim()
|
|
95
|
-
.slice(0, maxLength);
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
title,
|
|
99
|
-
text
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function extractReadableContentSafely(
|
|
104
|
-
html: string,
|
|
105
|
-
maxLength = 4000
|
|
106
|
-
): SafeReadableExtraction {
|
|
107
|
-
try {
|
|
108
|
-
return {
|
|
109
|
-
mode: 'readability',
|
|
110
|
-
content: extractReadableContent(html, maxLength)
|
|
111
|
-
};
|
|
112
|
-
} catch {
|
|
113
|
-
return {
|
|
114
|
-
mode: 'fallback',
|
|
115
|
-
content: extractFallbackText(html, maxLength)
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
}
|
|
1
|
+
import { Readability } from '@mozilla/readability';
|
|
2
|
+
import { JSDOM, VirtualConsole } from 'jsdom';
|
|
3
|
+
import type { ExtractedContent } from '../types.js';
|
|
4
|
+
|
|
5
|
+
export type ReadableExtractionMode = 'readability' | 'fallback';
|
|
6
|
+
|
|
7
|
+
export type SafeReadableExtraction = {
|
|
8
|
+
mode: ReadableExtractionMode;
|
|
9
|
+
content: ExtractedContent;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export function extractReadableContent(html: string, maxLength = 4000): ExtractedContent {
|
|
13
|
+
let stylesheetError: Error | undefined;
|
|
14
|
+
const virtualConsole = new VirtualConsole();
|
|
15
|
+
|
|
16
|
+
virtualConsole.on('jsdomError', (error) => {
|
|
17
|
+
if (!stylesheetError && error.message.includes('Could not parse CSS stylesheet')) {
|
|
18
|
+
stylesheetError = error;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const dom = new JSDOM(html, {
|
|
23
|
+
url: 'https://example.com',
|
|
24
|
+
virtualConsole
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (stylesheetError) {
|
|
28
|
+
throw stylesheetError;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const article = new Readability(dom.window.document).parse();
|
|
32
|
+
const rawText = (article?.textContent ?? dom.window.document.body.textContent ?? '').trim();
|
|
33
|
+
const text = rawText.slice(0, maxLength);
|
|
34
|
+
|
|
35
|
+
const fallbackTitle = dom.window.document.title || undefined;
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
title: article?.title ?? fallbackTitle,
|
|
39
|
+
byline: article?.byline || undefined,
|
|
40
|
+
text
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function decodeHtmlEntities(text: string): string {
|
|
45
|
+
return text
|
|
46
|
+
.replace(/ /gi, ' ')
|
|
47
|
+
.replace(/&/gi, '&')
|
|
48
|
+
.replace(/</gi, '<')
|
|
49
|
+
.replace(/>/gi, '>')
|
|
50
|
+
.replace(/"/gi, '"')
|
|
51
|
+
.replace(/'/gi, "'")
|
|
52
|
+
.replace(/'/gi, "'")
|
|
53
|
+
.replace(///gi, '/')
|
|
54
|
+
.replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code)))
|
|
55
|
+
.replace(/&#x([\da-f]+);/gi, (_, code) => String.fromCharCode(parseInt(code, 16)));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function extractTitle(html: string): string | undefined {
|
|
59
|
+
const match = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
60
|
+
if (!match) return undefined;
|
|
61
|
+
return decodeHtmlEntities(match[1].replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim()) || undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function stripTagContent(html: string, tagName: string): string {
|
|
65
|
+
return html.replace(new RegExp(`<${tagName}\\b[^>]*>[\\s\\S]*?<\\/${tagName}>`, 'gi'), ' ');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function extractPreferredSection(html: string): string {
|
|
69
|
+
const mainMatch = html.match(/<main\b[^>]*>([\s\S]*?)<\/main>/i);
|
|
70
|
+
if (mainMatch) return mainMatch[1];
|
|
71
|
+
|
|
72
|
+
const articleMatch = html.match(/<article\b[^>]*>([\s\S]*?)<\/article>/i);
|
|
73
|
+
if (articleMatch) return articleMatch[1];
|
|
74
|
+
|
|
75
|
+
const bodyMatch = html.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
|
|
76
|
+
if (bodyMatch) return bodyMatch[1];
|
|
77
|
+
|
|
78
|
+
return html;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function extractFallbackText(html: string, maxLength: number): ExtractedContent {
|
|
82
|
+
const title = extractTitle(html);
|
|
83
|
+
let section = extractPreferredSection(html);
|
|
84
|
+
|
|
85
|
+
section = stripTagContent(section, 'script');
|
|
86
|
+
section = stripTagContent(section, 'style');
|
|
87
|
+
section = stripTagContent(section, 'noscript');
|
|
88
|
+
section = stripTagContent(section, 'svg');
|
|
89
|
+
section = stripTagContent(section, 'template');
|
|
90
|
+
|
|
91
|
+
const text = decodeHtmlEntities(section)
|
|
92
|
+
.replace(/<[^>]+>/g, ' ')
|
|
93
|
+
.replace(/\s+/g, ' ')
|
|
94
|
+
.trim()
|
|
95
|
+
.slice(0, maxLength);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
title,
|
|
99
|
+
text
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function extractReadableContentSafely(
|
|
104
|
+
html: string,
|
|
105
|
+
maxLength = 4000
|
|
106
|
+
): SafeReadableExtraction {
|
|
107
|
+
try {
|
|
108
|
+
return {
|
|
109
|
+
mode: 'readability',
|
|
110
|
+
content: extractReadableContent(html, maxLength)
|
|
111
|
+
};
|
|
112
|
+
} catch {
|
|
113
|
+
return {
|
|
114
|
+
mode: 'fallback',
|
|
115
|
+
content: extractFallbackText(html, maxLength)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|