@oh-my-pi/pi-coding-agent 0.1.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/CHANGELOG.md +1629 -0
- package/README.md +1041 -0
- package/docs/compaction.md +403 -0
- package/docs/config-usage.md +113 -0
- package/docs/custom-tools.md +541 -0
- package/docs/extension-loading.md +1004 -0
- package/docs/hooks.md +867 -0
- package/docs/rpc.md +1040 -0
- package/docs/sdk.md +994 -0
- package/docs/session-tree-plan.md +441 -0
- package/docs/session.md +240 -0
- package/docs/skills.md +290 -0
- package/docs/theme.md +670 -0
- package/docs/tree.md +197 -0
- package/docs/tui.md +341 -0
- package/examples/README.md +21 -0
- package/examples/custom-tools/README.md +124 -0
- package/examples/custom-tools/hello/index.ts +20 -0
- package/examples/custom-tools/question/index.ts +84 -0
- package/examples/custom-tools/subagent/README.md +172 -0
- package/examples/custom-tools/subagent/agents/planner.md +37 -0
- package/examples/custom-tools/subagent/agents/scout.md +50 -0
- package/examples/custom-tools/subagent/agents/worker.md +24 -0
- package/examples/custom-tools/subagent/agents.ts +156 -0
- package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
- package/examples/custom-tools/subagent/commands/implement.md +10 -0
- package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
- package/examples/custom-tools/subagent/index.ts +1002 -0
- package/examples/custom-tools/todo/index.ts +212 -0
- package/examples/hooks/README.md +56 -0
- package/examples/hooks/auto-commit-on-exit.ts +49 -0
- package/examples/hooks/confirm-destructive.ts +59 -0
- package/examples/hooks/custom-compaction.ts +116 -0
- package/examples/hooks/dirty-repo-guard.ts +52 -0
- package/examples/hooks/file-trigger.ts +41 -0
- package/examples/hooks/git-checkpoint.ts +53 -0
- package/examples/hooks/handoff.ts +150 -0
- package/examples/hooks/permission-gate.ts +34 -0
- package/examples/hooks/protected-paths.ts +30 -0
- package/examples/hooks/qna.ts +119 -0
- package/examples/hooks/snake.ts +343 -0
- package/examples/hooks/status-line.ts +40 -0
- package/examples/sdk/01-minimal.ts +22 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +44 -0
- package/examples/sdk/04-skills.ts +44 -0
- package/examples/sdk/05-tools.ts +90 -0
- package/examples/sdk/06-hooks.ts +61 -0
- package/examples/sdk/07-context-files.ts +36 -0
- package/examples/sdk/08-slash-commands.ts +42 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
- package/examples/sdk/10-settings.ts +38 -0
- package/examples/sdk/11-sessions.ts +48 -0
- package/examples/sdk/12-full-control.ts +95 -0
- package/examples/sdk/README.md +154 -0
- package/package.json +89 -0
- package/src/bun-imports.d.ts +16 -0
- package/src/capability/context-file.ts +40 -0
- package/src/capability/extension.ts +48 -0
- package/src/capability/hook.ts +40 -0
- package/src/capability/index.ts +616 -0
- package/src/capability/instruction.ts +37 -0
- package/src/capability/mcp.ts +52 -0
- package/src/capability/prompt.ts +35 -0
- package/src/capability/rule.ts +56 -0
- package/src/capability/settings.ts +35 -0
- package/src/capability/skill.ts +49 -0
- package/src/capability/slash-command.ts +40 -0
- package/src/capability/system-prompt.ts +35 -0
- package/src/capability/tool.ts +38 -0
- package/src/capability/types.ts +166 -0
- package/src/cli/args.ts +259 -0
- package/src/cli/file-processor.ts +121 -0
- package/src/cli/list-models.ts +104 -0
- package/src/cli/plugin-cli.ts +661 -0
- package/src/cli/session-picker.ts +41 -0
- package/src/cli/update-cli.ts +274 -0
- package/src/cli.ts +10 -0
- package/src/config.ts +391 -0
- package/src/core/agent-session.ts +2178 -0
- package/src/core/auth-storage.ts +258 -0
- package/src/core/bash-executor.ts +197 -0
- package/src/core/compaction/branch-summarization.ts +315 -0
- package/src/core/compaction/compaction.ts +664 -0
- package/src/core/compaction/index.ts +7 -0
- package/src/core/compaction/utils.ts +153 -0
- package/src/core/custom-commands/bundled/review/index.ts +156 -0
- package/src/core/custom-commands/index.ts +15 -0
- package/src/core/custom-commands/loader.ts +226 -0
- package/src/core/custom-commands/types.ts +112 -0
- package/src/core/custom-tools/index.ts +22 -0
- package/src/core/custom-tools/loader.ts +248 -0
- package/src/core/custom-tools/types.ts +185 -0
- package/src/core/custom-tools/wrapper.ts +29 -0
- package/src/core/exec.ts +139 -0
- package/src/core/export-html/index.ts +159 -0
- package/src/core/export-html/template.css +774 -0
- package/src/core/export-html/template.generated.ts +2 -0
- package/src/core/export-html/template.html +45 -0
- package/src/core/export-html/template.js +1185 -0
- package/src/core/export-html/template.macro.ts +24 -0
- package/src/core/file-mentions.ts +54 -0
- package/src/core/hooks/index.ts +16 -0
- package/src/core/hooks/loader.ts +288 -0
- package/src/core/hooks/runner.ts +434 -0
- package/src/core/hooks/tool-wrapper.ts +98 -0
- package/src/core/hooks/types.ts +770 -0
- package/src/core/index.ts +53 -0
- package/src/core/logger.ts +112 -0
- package/src/core/mcp/client.ts +185 -0
- package/src/core/mcp/config.ts +248 -0
- package/src/core/mcp/index.ts +45 -0
- package/src/core/mcp/loader.ts +99 -0
- package/src/core/mcp/manager.ts +235 -0
- package/src/core/mcp/tool-bridge.ts +156 -0
- package/src/core/mcp/transports/http.ts +316 -0
- package/src/core/mcp/transports/index.ts +6 -0
- package/src/core/mcp/transports/stdio.ts +252 -0
- package/src/core/mcp/types.ts +228 -0
- package/src/core/messages.ts +211 -0
- package/src/core/model-registry.ts +334 -0
- package/src/core/model-resolver.ts +494 -0
- package/src/core/plugins/doctor.ts +67 -0
- package/src/core/plugins/index.ts +38 -0
- package/src/core/plugins/installer.ts +189 -0
- package/src/core/plugins/loader.ts +339 -0
- package/src/core/plugins/manager.ts +672 -0
- package/src/core/plugins/parser.ts +105 -0
- package/src/core/plugins/paths.ts +37 -0
- package/src/core/plugins/types.ts +190 -0
- package/src/core/sdk.ts +900 -0
- package/src/core/session-manager.ts +1837 -0
- package/src/core/settings-manager.ts +860 -0
- package/src/core/skills.ts +352 -0
- package/src/core/slash-commands.ts +132 -0
- package/src/core/system-prompt.ts +442 -0
- package/src/core/timings.ts +25 -0
- package/src/core/title-generator.ts +110 -0
- package/src/core/tools/ask.ts +193 -0
- package/src/core/tools/bash-interceptor.ts +120 -0
- package/src/core/tools/bash.ts +91 -0
- package/src/core/tools/context.ts +32 -0
- package/src/core/tools/edit-diff.ts +487 -0
- package/src/core/tools/edit.ts +140 -0
- package/src/core/tools/exa/company.ts +59 -0
- package/src/core/tools/exa/index.ts +63 -0
- package/src/core/tools/exa/linkedin.ts +59 -0
- package/src/core/tools/exa/mcp-client.ts +368 -0
- package/src/core/tools/exa/render.ts +200 -0
- package/src/core/tools/exa/researcher.ts +90 -0
- package/src/core/tools/exa/search.ts +338 -0
- package/src/core/tools/exa/types.ts +167 -0
- package/src/core/tools/exa/websets.ts +248 -0
- package/src/core/tools/find.ts +244 -0
- package/src/core/tools/grep.ts +584 -0
- package/src/core/tools/index.ts +283 -0
- package/src/core/tools/ls.ts +142 -0
- package/src/core/tools/lsp/client.ts +767 -0
- package/src/core/tools/lsp/clients/biome-client.ts +207 -0
- package/src/core/tools/lsp/clients/index.ts +49 -0
- package/src/core/tools/lsp/clients/lsp-linter-client.ts +98 -0
- package/src/core/tools/lsp/config.ts +845 -0
- package/src/core/tools/lsp/edits.ts +110 -0
- package/src/core/tools/lsp/index.ts +1364 -0
- package/src/core/tools/lsp/render.ts +560 -0
- package/src/core/tools/lsp/rust-analyzer.ts +145 -0
- package/src/core/tools/lsp/types.ts +495 -0
- package/src/core/tools/lsp/utils.ts +526 -0
- package/src/core/tools/notebook.ts +182 -0
- package/src/core/tools/output.ts +198 -0
- package/src/core/tools/path-utils.ts +61 -0
- package/src/core/tools/read.ts +507 -0
- package/src/core/tools/renderers.ts +820 -0
- package/src/core/tools/review.ts +275 -0
- package/src/core/tools/rulebook.ts +124 -0
- package/src/core/tools/task/agents.ts +158 -0
- package/src/core/tools/task/artifacts.ts +114 -0
- package/src/core/tools/task/commands.ts +157 -0
- package/src/core/tools/task/discovery.ts +217 -0
- package/src/core/tools/task/executor.ts +531 -0
- package/src/core/tools/task/index.ts +548 -0
- package/src/core/tools/task/model-resolver.ts +176 -0
- package/src/core/tools/task/parallel.ts +38 -0
- package/src/core/tools/task/render.ts +502 -0
- package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
- package/src/core/tools/task/types.ts +142 -0
- package/src/core/tools/truncate.ts +265 -0
- package/src/core/tools/web-fetch.ts +2511 -0
- package/src/core/tools/web-search/auth.ts +199 -0
- package/src/core/tools/web-search/index.ts +583 -0
- package/src/core/tools/web-search/providers/anthropic.ts +198 -0
- package/src/core/tools/web-search/providers/exa.ts +196 -0
- package/src/core/tools/web-search/providers/perplexity.ts +195 -0
- package/src/core/tools/web-search/render.ts +372 -0
- package/src/core/tools/web-search/types.ts +180 -0
- package/src/core/tools/write.ts +63 -0
- package/src/core/ttsr.ts +211 -0
- package/src/core/utils.ts +187 -0
- package/src/discovery/agents-md.ts +75 -0
- package/src/discovery/builtin.ts +647 -0
- package/src/discovery/claude.ts +623 -0
- package/src/discovery/cline.ts +104 -0
- package/src/discovery/codex.ts +571 -0
- package/src/discovery/cursor.ts +266 -0
- package/src/discovery/gemini.ts +368 -0
- package/src/discovery/github.ts +120 -0
- package/src/discovery/helpers.test.ts +127 -0
- package/src/discovery/helpers.ts +249 -0
- package/src/discovery/index.ts +84 -0
- package/src/discovery/mcp-json.ts +127 -0
- package/src/discovery/vscode.ts +99 -0
- package/src/discovery/windsurf.ts +219 -0
- package/src/index.ts +192 -0
- package/src/main.ts +507 -0
- package/src/migrations.ts +156 -0
- package/src/modes/cleanup.ts +23 -0
- package/src/modes/index.ts +48 -0
- package/src/modes/interactive/components/armin.ts +382 -0
- package/src/modes/interactive/components/assistant-message.ts +86 -0
- package/src/modes/interactive/components/bash-execution.ts +199 -0
- package/src/modes/interactive/components/bordered-loader.ts +41 -0
- package/src/modes/interactive/components/branch-summary-message.ts +42 -0
- package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
- package/src/modes/interactive/components/custom-editor.ts +122 -0
- package/src/modes/interactive/components/diff.ts +147 -0
- package/src/modes/interactive/components/dynamic-border.ts +25 -0
- package/src/modes/interactive/components/extensions/extension-dashboard.ts +296 -0
- package/src/modes/interactive/components/extensions/extension-list.ts +479 -0
- package/src/modes/interactive/components/extensions/index.ts +9 -0
- package/src/modes/interactive/components/extensions/inspector-panel.ts +313 -0
- package/src/modes/interactive/components/extensions/state-manager.ts +558 -0
- package/src/modes/interactive/components/extensions/types.ts +191 -0
- package/src/modes/interactive/components/hook-editor.ts +117 -0
- package/src/modes/interactive/components/hook-input.ts +64 -0
- package/src/modes/interactive/components/hook-message.ts +96 -0
- package/src/modes/interactive/components/hook-selector.ts +91 -0
- package/src/modes/interactive/components/model-selector.ts +560 -0
- package/src/modes/interactive/components/oauth-selector.ts +136 -0
- package/src/modes/interactive/components/plugin-settings.ts +481 -0
- package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
- package/src/modes/interactive/components/session-selector.ts +220 -0
- package/src/modes/interactive/components/settings-defs.ts +597 -0
- package/src/modes/interactive/components/settings-selector.ts +545 -0
- package/src/modes/interactive/components/show-images-selector.ts +45 -0
- package/src/modes/interactive/components/status-line/index.ts +4 -0
- package/src/modes/interactive/components/status-line/presets.ts +94 -0
- package/src/modes/interactive/components/status-line/segments.ts +350 -0
- package/src/modes/interactive/components/status-line/separators.ts +55 -0
- package/src/modes/interactive/components/status-line/types.ts +81 -0
- package/src/modes/interactive/components/status-line-segment-editor.ts +357 -0
- package/src/modes/interactive/components/status-line.ts +384 -0
- package/src/modes/interactive/components/theme-selector.ts +62 -0
- package/src/modes/interactive/components/thinking-selector.ts +64 -0
- package/src/modes/interactive/components/tool-execution.ts +946 -0
- package/src/modes/interactive/components/tree-selector.ts +877 -0
- package/src/modes/interactive/components/ttsr-notification.ts +82 -0
- package/src/modes/interactive/components/user-message-selector.ts +159 -0
- package/src/modes/interactive/components/user-message.ts +18 -0
- package/src/modes/interactive/components/visual-truncate.ts +50 -0
- package/src/modes/interactive/components/welcome.ts +228 -0
- package/src/modes/interactive/interactive-mode.ts +2669 -0
- package/src/modes/interactive/theme/dark.json +102 -0
- package/src/modes/interactive/theme/defaults/dark-arctic.json +111 -0
- package/src/modes/interactive/theme/defaults/dark-catppuccin.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +109 -0
- package/src/modes/interactive/theme/defaults/dark-dracula.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-forest.json +103 -0
- package/src/modes/interactive/theme/defaults/dark-github.json +112 -0
- package/src/modes/interactive/theme/defaults/dark-gruvbox.json +119 -0
- package/src/modes/interactive/theme/defaults/dark-monochrome.json +101 -0
- package/src/modes/interactive/theme/defaults/dark-monokai.json +105 -0
- package/src/modes/interactive/theme/defaults/dark-nord.json +104 -0
- package/src/modes/interactive/theme/defaults/dark-ocean.json +108 -0
- package/src/modes/interactive/theme/defaults/dark-one.json +107 -0
- package/src/modes/interactive/theme/defaults/dark-retro.json +99 -0
- package/src/modes/interactive/theme/defaults/dark-rose-pine.json +95 -0
- package/src/modes/interactive/theme/defaults/dark-solarized.json +96 -0
- package/src/modes/interactive/theme/defaults/dark-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/dark-synthwave.json +102 -0
- package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +108 -0
- package/src/modes/interactive/theme/defaults/index.ts +67 -0
- package/src/modes/interactive/theme/defaults/light-arctic.json +106 -0
- package/src/modes/interactive/theme/defaults/light-catppuccin.json +105 -0
- package/src/modes/interactive/theme/defaults/light-cyberpunk.json +103 -0
- package/src/modes/interactive/theme/defaults/light-forest.json +107 -0
- package/src/modes/interactive/theme/defaults/light-github.json +114 -0
- package/src/modes/interactive/theme/defaults/light-gruvbox.json +115 -0
- package/src/modes/interactive/theme/defaults/light-monochrome.json +100 -0
- package/src/modes/interactive/theme/defaults/light-ocean.json +106 -0
- package/src/modes/interactive/theme/defaults/light-one.json +105 -0
- package/src/modes/interactive/theme/defaults/light-retro.json +105 -0
- package/src/modes/interactive/theme/defaults/light-solarized.json +101 -0
- package/src/modes/interactive/theme/defaults/light-sunset.json +106 -0
- package/src/modes/interactive/theme/defaults/light-synthwave.json +105 -0
- package/src/modes/interactive/theme/defaults/light-tokyo-night.json +118 -0
- package/src/modes/interactive/theme/light.json +99 -0
- package/src/modes/interactive/theme/theme-schema.json +424 -0
- package/src/modes/interactive/theme/theme.ts +2211 -0
- package/src/modes/print-mode.ts +163 -0
- package/src/modes/rpc/rpc-client.ts +527 -0
- package/src/modes/rpc/rpc-mode.ts +494 -0
- package/src/modes/rpc/rpc-types.ts +203 -0
- package/src/prompts/architect-plan.md +10 -0
- package/src/prompts/branch-summary-preamble.md +3 -0
- package/src/prompts/branch-summary.md +28 -0
- package/src/prompts/browser.md +71 -0
- package/src/prompts/compaction-summary.md +34 -0
- package/src/prompts/compaction-turn-prefix.md +16 -0
- package/src/prompts/compaction-update-summary.md +41 -0
- package/src/prompts/explore.md +82 -0
- package/src/prompts/implement-with-critic.md +11 -0
- package/src/prompts/implement.md +11 -0
- package/src/prompts/init.md +30 -0
- package/src/prompts/plan.md +54 -0
- package/src/prompts/reviewer.md +81 -0
- package/src/prompts/summarization-system.md +3 -0
- package/src/prompts/system-prompt.md +27 -0
- package/src/prompts/task.md +56 -0
- package/src/prompts/title-system.md +8 -0
- package/src/prompts/tools/ask.md +24 -0
- package/src/prompts/tools/bash.md +23 -0
- package/src/prompts/tools/edit.md +9 -0
- package/src/prompts/tools/find.md +6 -0
- package/src/prompts/tools/grep.md +12 -0
- package/src/prompts/tools/lsp.md +14 -0
- package/src/prompts/tools/output.md +23 -0
- package/src/prompts/tools/read.md +25 -0
- package/src/prompts/tools/web-fetch.md +8 -0
- package/src/prompts/tools/web-search.md +10 -0
- package/src/prompts/tools/write.md +10 -0
- package/src/utils/changelog.ts +99 -0
- package/src/utils/clipboard.ts +265 -0
- package/src/utils/fuzzy.ts +108 -0
- package/src/utils/mime.ts +30 -0
- package/src/utils/shell-snapshot.ts +218 -0
- package/src/utils/shell.ts +364 -0
- package/src/utils/tools-manager.ts +265 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Extension Control Center dashboard.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { SourceMeta } from "../../../../capability/types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extension kinds matching capability types.
|
|
9
|
+
*/
|
|
10
|
+
export type ExtensionKind =
|
|
11
|
+
| "skill"
|
|
12
|
+
| "rule"
|
|
13
|
+
| "tool"
|
|
14
|
+
| "mcp"
|
|
15
|
+
| "prompt"
|
|
16
|
+
| "instruction"
|
|
17
|
+
| "context-file"
|
|
18
|
+
| "hook"
|
|
19
|
+
| "slash-command";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Extension state (active, disabled, or shadowed).
|
|
23
|
+
*/
|
|
24
|
+
export type ExtensionState = "active" | "disabled" | "shadowed";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Reason why an extension is disabled.
|
|
28
|
+
*/
|
|
29
|
+
export type DisabledReason = "provider-disabled" | "item-disabled" | "shadowed";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Unified extension representation for the dashboard.
|
|
33
|
+
* Normalizes all capability types into a common shape.
|
|
34
|
+
*/
|
|
35
|
+
export interface Extension {
|
|
36
|
+
/** Unique ID: `${kind}:${name}` */
|
|
37
|
+
id: string;
|
|
38
|
+
/** Extension kind */
|
|
39
|
+
kind: ExtensionKind;
|
|
40
|
+
/** Extension name */
|
|
41
|
+
name: string;
|
|
42
|
+
/** Display name (may differ from name) */
|
|
43
|
+
displayName: string;
|
|
44
|
+
/** Description if available */
|
|
45
|
+
description?: string;
|
|
46
|
+
/** Trigger pattern (slash command, glob, regex) */
|
|
47
|
+
trigger?: string;
|
|
48
|
+
/** Absolute path to source file */
|
|
49
|
+
path: string;
|
|
50
|
+
/** Source metadata */
|
|
51
|
+
source: {
|
|
52
|
+
provider: string;
|
|
53
|
+
providerName: string;
|
|
54
|
+
level: "user" | "project" | "native";
|
|
55
|
+
};
|
|
56
|
+
/** Current state */
|
|
57
|
+
state: ExtensionState;
|
|
58
|
+
/** Reason for disabled state */
|
|
59
|
+
disabledReason?: DisabledReason;
|
|
60
|
+
/** If shadowed, what shadows it */
|
|
61
|
+
shadowedBy?: string;
|
|
62
|
+
/** Raw item data for inspector */
|
|
63
|
+
raw: unknown;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Tree node types for sidebar hierarchy.
|
|
68
|
+
*/
|
|
69
|
+
export type TreeNodeType = "provider" | "kind" | "item";
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Sidebar tree node.
|
|
73
|
+
*/
|
|
74
|
+
export interface TreeNode {
|
|
75
|
+
/** Unique ID */
|
|
76
|
+
id: string;
|
|
77
|
+
/** Display label */
|
|
78
|
+
label: string;
|
|
79
|
+
/** Node type (provider can be toggled, kind groups items) */
|
|
80
|
+
type: TreeNodeType;
|
|
81
|
+
/** Whether this node/provider is enabled */
|
|
82
|
+
enabled: boolean;
|
|
83
|
+
/** Whether collapsed */
|
|
84
|
+
collapsed: boolean;
|
|
85
|
+
/** Child nodes */
|
|
86
|
+
children: TreeNode[];
|
|
87
|
+
/** Extension count (for display) */
|
|
88
|
+
count?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Flattened tree item for navigation.
|
|
93
|
+
*/
|
|
94
|
+
export interface FlatTreeItem {
|
|
95
|
+
node: TreeNode;
|
|
96
|
+
depth: number;
|
|
97
|
+
index: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Focus region in the tabbed dashboard.
|
|
102
|
+
*/
|
|
103
|
+
export type FocusRegion = "tabs" | "list";
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Provider tab representation.
|
|
107
|
+
*/
|
|
108
|
+
export interface ProviderTab {
|
|
109
|
+
/** Provider ID (or "all" for the ALL tab) */
|
|
110
|
+
id: string;
|
|
111
|
+
/** Display label */
|
|
112
|
+
label: string;
|
|
113
|
+
/** Whether provider is enabled (always true for "all") */
|
|
114
|
+
enabled: boolean;
|
|
115
|
+
/** Extension count for this provider */
|
|
116
|
+
count: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Tabbed dashboard state.
|
|
121
|
+
*/
|
|
122
|
+
export interface DashboardState {
|
|
123
|
+
/** Provider tabs */
|
|
124
|
+
tabs: ProviderTab[];
|
|
125
|
+
/** Active tab index */
|
|
126
|
+
activeTabIndex: number;
|
|
127
|
+
|
|
128
|
+
/** All extensions (unfiltered) */
|
|
129
|
+
extensions: Extension[];
|
|
130
|
+
/** Extensions filtered by active tab */
|
|
131
|
+
tabFiltered: Extension[];
|
|
132
|
+
/** Extensions filtered by search (applied after tab filter) */
|
|
133
|
+
searchFiltered: Extension[];
|
|
134
|
+
/** Current search query */
|
|
135
|
+
searchQuery: string;
|
|
136
|
+
|
|
137
|
+
/** Selected index in main list */
|
|
138
|
+
listIndex: number;
|
|
139
|
+
/** Scroll offset for main list */
|
|
140
|
+
scrollOffset: number;
|
|
141
|
+
|
|
142
|
+
/** Currently selected extension for inspector */
|
|
143
|
+
selected: Extension | null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @deprecated Use FocusRegion instead
|
|
148
|
+
*/
|
|
149
|
+
export type FocusPane = "sidebar" | "main" | "inspector";
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Callbacks from dashboard to parent.
|
|
153
|
+
*/
|
|
154
|
+
export interface DashboardCallbacks {
|
|
155
|
+
/** Called when provider is toggled */
|
|
156
|
+
onProviderToggle: (providerId: string, enabled: boolean) => void;
|
|
157
|
+
/** Called when extension item is toggled */
|
|
158
|
+
onExtensionToggle: (extensionId: string, enabled: boolean) => void;
|
|
159
|
+
/** Called when dashboard is closed */
|
|
160
|
+
onClose: () => void;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Create extension ID from kind and name.
|
|
165
|
+
*/
|
|
166
|
+
export function makeExtensionId(kind: ExtensionKind, name: string): string {
|
|
167
|
+
return `${kind}:${name}`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Parse extension ID into kind and name.
|
|
172
|
+
*/
|
|
173
|
+
export function parseExtensionId(id: string): { kind: ExtensionKind; name: string } | null {
|
|
174
|
+
const colonIdx = id.indexOf(":");
|
|
175
|
+
if (colonIdx === -1) return null;
|
|
176
|
+
return {
|
|
177
|
+
kind: id.slice(0, colonIdx) as ExtensionKind,
|
|
178
|
+
name: id.slice(colonIdx + 1),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Map SourceMeta to extension source shape.
|
|
184
|
+
*/
|
|
185
|
+
export function sourceFromMeta(meta: SourceMeta): Extension["source"] {
|
|
186
|
+
return {
|
|
187
|
+
provider: meta.provider,
|
|
188
|
+
providerName: meta.providerName,
|
|
189
|
+
level: meta.level,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-line editor component for hooks.
|
|
3
|
+
* Supports Ctrl+G for external editor.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from "node:fs";
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { Container, Editor, isCtrlG, isEscape, Spacer, Text, type TUI } from "@oh-my-pi/pi-tui";
|
|
10
|
+
import { getEditorTheme, theme } from "../theme/theme";
|
|
11
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
12
|
+
|
|
13
|
+
export class HookEditorComponent extends Container {
|
|
14
|
+
private editor: Editor;
|
|
15
|
+
private onSubmitCallback: (value: string) => void;
|
|
16
|
+
private onCancelCallback: () => void;
|
|
17
|
+
private tui: TUI;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
tui: TUI,
|
|
21
|
+
title: string,
|
|
22
|
+
prefill: string | undefined,
|
|
23
|
+
onSubmit: (value: string) => void,
|
|
24
|
+
onCancel: () => void,
|
|
25
|
+
) {
|
|
26
|
+
super();
|
|
27
|
+
|
|
28
|
+
this.tui = tui;
|
|
29
|
+
this.onSubmitCallback = onSubmit;
|
|
30
|
+
this.onCancelCallback = onCancel;
|
|
31
|
+
|
|
32
|
+
// Add top border
|
|
33
|
+
this.addChild(new DynamicBorder());
|
|
34
|
+
this.addChild(new Spacer(1));
|
|
35
|
+
|
|
36
|
+
// Add title
|
|
37
|
+
this.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
38
|
+
this.addChild(new Spacer(1));
|
|
39
|
+
|
|
40
|
+
// Create editor
|
|
41
|
+
this.editor = new Editor(getEditorTheme());
|
|
42
|
+
if (prefill) {
|
|
43
|
+
this.editor.setText(prefill);
|
|
44
|
+
}
|
|
45
|
+
this.addChild(this.editor);
|
|
46
|
+
|
|
47
|
+
this.addChild(new Spacer(1));
|
|
48
|
+
|
|
49
|
+
// Add hint
|
|
50
|
+
const hasExternalEditor = !!(process.env.VISUAL || process.env.EDITOR);
|
|
51
|
+
const hint = hasExternalEditor
|
|
52
|
+
? "ctrl+enter submit esc cancel ctrl+g external editor"
|
|
53
|
+
: "ctrl+enter submit esc cancel";
|
|
54
|
+
this.addChild(new Text(theme.fg("dim", hint), 1, 0));
|
|
55
|
+
|
|
56
|
+
this.addChild(new Spacer(1));
|
|
57
|
+
|
|
58
|
+
// Add bottom border
|
|
59
|
+
this.addChild(new DynamicBorder());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
handleInput(keyData: string): void {
|
|
63
|
+
// Ctrl+Enter to submit
|
|
64
|
+
if (keyData === "\x1b[13;5u" || keyData === "\x1b[27;5;13~") {
|
|
65
|
+
this.onSubmitCallback(this.editor.getText());
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Escape to cancel
|
|
70
|
+
if (isEscape(keyData)) {
|
|
71
|
+
this.onCancelCallback();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Ctrl+G for external editor
|
|
76
|
+
if (isCtrlG(keyData)) {
|
|
77
|
+
this.openExternalEditor();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Forward to editor
|
|
82
|
+
this.editor.handleInput(keyData);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private openExternalEditor(): void {
|
|
86
|
+
const editorCmd = process.env.VISUAL || process.env.EDITOR;
|
|
87
|
+
if (!editorCmd) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const currentText = this.editor.getText();
|
|
92
|
+
const tmpFile = path.join(os.tmpdir(), `omp-hook-editor-${Date.now()}.md`);
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
fs.writeFileSync(tmpFile, currentText, "utf-8");
|
|
96
|
+
this.tui.stop();
|
|
97
|
+
|
|
98
|
+
const [editor, ...editorArgs] = editorCmd.split(" ");
|
|
99
|
+
const result = Bun.spawnSync([editor, ...editorArgs, tmpFile], {
|
|
100
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
if (result.exitCode === 0) {
|
|
104
|
+
const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
|
|
105
|
+
this.editor.setText(newContent);
|
|
106
|
+
}
|
|
107
|
+
} finally {
|
|
108
|
+
try {
|
|
109
|
+
fs.unlinkSync(tmpFile);
|
|
110
|
+
} catch {
|
|
111
|
+
// Ignore cleanup errors
|
|
112
|
+
}
|
|
113
|
+
this.tui.start();
|
|
114
|
+
this.tui.requestRender();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple text input component for hooks.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Container, Input, isEnter, isEscape, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
6
|
+
import { theme } from "../theme/theme";
|
|
7
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
8
|
+
|
|
9
|
+
export class HookInputComponent extends Container {
|
|
10
|
+
private input: Input;
|
|
11
|
+
private onSubmitCallback: (value: string) => void;
|
|
12
|
+
private onCancelCallback: () => void;
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
title: string,
|
|
16
|
+
_placeholder: string | undefined,
|
|
17
|
+
onSubmit: (value: string) => void,
|
|
18
|
+
onCancel: () => void,
|
|
19
|
+
) {
|
|
20
|
+
super();
|
|
21
|
+
|
|
22
|
+
this.onSubmitCallback = onSubmit;
|
|
23
|
+
this.onCancelCallback = onCancel;
|
|
24
|
+
|
|
25
|
+
// Add top border
|
|
26
|
+
this.addChild(new DynamicBorder());
|
|
27
|
+
this.addChild(new Spacer(1));
|
|
28
|
+
|
|
29
|
+
// Add title
|
|
30
|
+
this.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
31
|
+
this.addChild(new Spacer(1));
|
|
32
|
+
|
|
33
|
+
// Create input
|
|
34
|
+
this.input = new Input();
|
|
35
|
+
this.addChild(this.input);
|
|
36
|
+
|
|
37
|
+
this.addChild(new Spacer(1));
|
|
38
|
+
|
|
39
|
+
// Add hint
|
|
40
|
+
this.addChild(new Text(theme.fg("dim", "enter submit esc cancel"), 1, 0));
|
|
41
|
+
|
|
42
|
+
this.addChild(new Spacer(1));
|
|
43
|
+
|
|
44
|
+
// Add bottom border
|
|
45
|
+
this.addChild(new DynamicBorder());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
handleInput(keyData: string): void {
|
|
49
|
+
// Enter
|
|
50
|
+
if (isEnter(keyData) || keyData === "\n") {
|
|
51
|
+
this.onSubmitCallback(this.input.getValue());
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Escape to cancel
|
|
56
|
+
if (isEscape(keyData)) {
|
|
57
|
+
this.onCancelCallback();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Forward to input
|
|
62
|
+
this.input.handleInput(keyData);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { TextContent } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { Box, Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
4
|
+
import type { HookMessageRenderer } from "../../../core/hooks/types";
|
|
5
|
+
import type { HookMessage } from "../../../core/messages";
|
|
6
|
+
import { getMarkdownTheme, theme } from "../theme/theme";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Component that renders a custom message entry from hooks.
|
|
10
|
+
* Uses distinct styling to differentiate from user messages.
|
|
11
|
+
*/
|
|
12
|
+
export class HookMessageComponent extends Container {
|
|
13
|
+
private message: HookMessage<unknown>;
|
|
14
|
+
private customRenderer?: HookMessageRenderer;
|
|
15
|
+
private box: Box;
|
|
16
|
+
private customComponent?: Component;
|
|
17
|
+
private _expanded = false;
|
|
18
|
+
|
|
19
|
+
constructor(message: HookMessage<unknown>, customRenderer?: HookMessageRenderer) {
|
|
20
|
+
super();
|
|
21
|
+
this.message = message;
|
|
22
|
+
this.customRenderer = customRenderer;
|
|
23
|
+
|
|
24
|
+
this.addChild(new Spacer(1));
|
|
25
|
+
|
|
26
|
+
// Create box with purple background (used for default rendering)
|
|
27
|
+
this.box = new Box(1, 1, (t) => theme.bg("customMessageBg", t));
|
|
28
|
+
|
|
29
|
+
this.rebuild();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setExpanded(expanded: boolean): void {
|
|
33
|
+
if (this._expanded !== expanded) {
|
|
34
|
+
this._expanded = expanded;
|
|
35
|
+
this.rebuild();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private rebuild(): void {
|
|
40
|
+
// Remove previous content component
|
|
41
|
+
if (this.customComponent) {
|
|
42
|
+
this.removeChild(this.customComponent);
|
|
43
|
+
this.customComponent = undefined;
|
|
44
|
+
}
|
|
45
|
+
this.removeChild(this.box);
|
|
46
|
+
|
|
47
|
+
// Try custom renderer first - it handles its own styling
|
|
48
|
+
if (this.customRenderer) {
|
|
49
|
+
try {
|
|
50
|
+
const component = this.customRenderer(this.message, { expanded: this._expanded }, theme);
|
|
51
|
+
if (component) {
|
|
52
|
+
// Custom renderer provides its own styled component
|
|
53
|
+
this.customComponent = component;
|
|
54
|
+
this.addChild(component);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// Fall through to default rendering
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Default rendering uses our box
|
|
63
|
+
this.addChild(this.box);
|
|
64
|
+
this.box.clear();
|
|
65
|
+
|
|
66
|
+
// Default rendering: label + content
|
|
67
|
+
const label = theme.fg("customMessageLabel", theme.bold(`[${this.message.customType}]`));
|
|
68
|
+
this.box.addChild(new Text(label, 0, 0));
|
|
69
|
+
this.box.addChild(new Spacer(1));
|
|
70
|
+
|
|
71
|
+
// Extract text content
|
|
72
|
+
let text: string;
|
|
73
|
+
if (typeof this.message.content === "string") {
|
|
74
|
+
text = this.message.content;
|
|
75
|
+
} else {
|
|
76
|
+
text = this.message.content
|
|
77
|
+
.filter((c): c is TextContent => c.type === "text")
|
|
78
|
+
.map((c) => c.text)
|
|
79
|
+
.join("\n");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Limit lines when collapsed
|
|
83
|
+
if (!this._expanded) {
|
|
84
|
+
const lines = text.split("\n");
|
|
85
|
+
if (lines.length > 5) {
|
|
86
|
+
text = `${lines.slice(0, 5).join("\n")}\n${theme.format.ellipsis}`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.box.addChild(
|
|
91
|
+
new Markdown(text, 0, 0, getMarkdownTheme(), {
|
|
92
|
+
color: (text: string) => theme.fg("customMessageText", text),
|
|
93
|
+
}),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic selector component for hooks.
|
|
3
|
+
* Displays a list of string options with keyboard navigation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Container, isArrowDown, isArrowUp, isEnter, isEscape, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import { theme } from "../theme/theme";
|
|
8
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
9
|
+
|
|
10
|
+
export class HookSelectorComponent extends Container {
|
|
11
|
+
private options: string[];
|
|
12
|
+
private selectedIndex = 0;
|
|
13
|
+
private listContainer: Container;
|
|
14
|
+
private onSelectCallback: (option: string) => void;
|
|
15
|
+
private onCancelCallback: () => void;
|
|
16
|
+
|
|
17
|
+
constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void) {
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.onSelectCallback = onSelect;
|
|
22
|
+
this.onCancelCallback = onCancel;
|
|
23
|
+
|
|
24
|
+
// Add top border
|
|
25
|
+
this.addChild(new DynamicBorder());
|
|
26
|
+
this.addChild(new Spacer(1));
|
|
27
|
+
|
|
28
|
+
// Add title
|
|
29
|
+
this.addChild(new Text(theme.fg("accent", title), 1, 0));
|
|
30
|
+
this.addChild(new Spacer(1));
|
|
31
|
+
|
|
32
|
+
// Create list container
|
|
33
|
+
this.listContainer = new Container();
|
|
34
|
+
this.addChild(this.listContainer);
|
|
35
|
+
|
|
36
|
+
this.addChild(new Spacer(1));
|
|
37
|
+
|
|
38
|
+
// Add hint
|
|
39
|
+
this.addChild(new Text(theme.fg("dim", "↑↓ navigate enter select esc cancel"), 1, 0));
|
|
40
|
+
|
|
41
|
+
this.addChild(new Spacer(1));
|
|
42
|
+
|
|
43
|
+
// Add bottom border
|
|
44
|
+
this.addChild(new DynamicBorder());
|
|
45
|
+
|
|
46
|
+
// Initial render
|
|
47
|
+
this.updateList();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private updateList(): void {
|
|
51
|
+
this.listContainer.clear();
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < this.options.length; i++) {
|
|
54
|
+
const option = this.options[i];
|
|
55
|
+
const isSelected = i === this.selectedIndex;
|
|
56
|
+
|
|
57
|
+
let text = "";
|
|
58
|
+
if (isSelected) {
|
|
59
|
+
text = theme.fg("accent", `${theme.nav.cursor} `) + theme.fg("accent", option);
|
|
60
|
+
} else {
|
|
61
|
+
text = ` ${theme.fg("text", option)}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.listContainer.addChild(new Text(text, 1, 0));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
handleInput(keyData: string): void {
|
|
69
|
+
// Up arrow or k
|
|
70
|
+
if (isArrowUp(keyData) || keyData === "k") {
|
|
71
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
72
|
+
this.updateList();
|
|
73
|
+
}
|
|
74
|
+
// Down arrow or j
|
|
75
|
+
else if (isArrowDown(keyData) || keyData === "j") {
|
|
76
|
+
this.selectedIndex = Math.min(this.options.length - 1, this.selectedIndex + 1);
|
|
77
|
+
this.updateList();
|
|
78
|
+
}
|
|
79
|
+
// Enter
|
|
80
|
+
else if (isEnter(keyData) || keyData === "\n") {
|
|
81
|
+
const selected = this.options[this.selectedIndex];
|
|
82
|
+
if (selected) {
|
|
83
|
+
this.onSelectCallback(selected);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Escape
|
|
87
|
+
else if (isEscape(keyData)) {
|
|
88
|
+
this.onCancelCallback();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|