omp-mode-switch 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # omp-mode-switch
2
+
3
+ [![npm version](https://img.shields.io/npm/v/omp-mode-switch)](https://www.npmjs.com/package/omp-mode-switch)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ An OMP plugin that lets you switch between three permission modes at runtime. Press **Tab** to cycle, or use `/mode <ask|auto|plan>`.
7
+
8
+ ---
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ omp plugin install omp-mode-switch
14
+ ```
15
+
16
+ Restart OMP (or start a new session) to activate.
17
+
18
+ ### Manual
19
+
20
+ Copy `mode-switch.ts` to `~/.omp/agent/extensions/` or your project's `.omp/extensions/`.
21
+
22
+ ## Usage
23
+
24
+ ### Modes
25
+
26
+ | Mode | Behavior |
27
+ |--------|----------|
28
+ | `ask` | Every tool call prompts for your confirmation (default) |
29
+ | `auto` | All tool calls are approved automatically |
30
+ | `plan` | Read-only tools only + `.md` file writing. Dangerous `bash` commands are blocked |
31
+
32
+ ### Switching
33
+
34
+ | Action | Effect |
35
+ |--------------|--------|
36
+ | **Tab** | Cycle: `ask → auto → plan → ask` |
37
+ | `/mode ask` | Switch to ask mode |
38
+ | `/mode auto` | Switch to auto mode |
39
+ | `/mode plan` | Switch to plan mode |
40
+
41
+ ### Status indicator
42
+
43
+ The current mode is shown as a colored widget at the bottom of the editor area:
44
+
45
+ - **ASK** (yellow)
46
+ - **AUTO** (green)
47
+ - **PLAN** (blue-cyan)
48
+
49
+ ## Example workflow
50
+
51
+ 1. **Explore** — Use `plan` mode to read through the codebase safely
52
+ 2. **Plan** — Write `.md` plans in `plan` mode
53
+ 3. **Execute** — Switch to `auto` to run changes
54
+ 4. **Review** — Switch to `ask` for step-by-step confirmation on critical operations
55
+
56
+ The mode resets to `ask` on each new session.
57
+
58
+ ## How it works
59
+
60
+ - Registers a **Tab** shortcut via `pi.registerShortcut()`
61
+ - Registers a `/mode` command via `pi.registerCommand()`
62
+ - Intercepts `tool_call` events to block destructive tools in `plan` mode
63
+ - Restricts tools via `pi.setActiveTools()` in plan mode
64
+ - Shows status via `ctx.ui.setWidget()` with colored text
65
+
66
+ ## Development
67
+
68
+ ```bash
69
+ git clone https://github.com/your-username/omp-mode-switch.git
70
+ cd omp-mode-switch
71
+ # Make changes to mode-switch.ts
72
+ # Copy to ~/.omp/agent/extensions/ and restart OMP to test
73
+ ```
74
+
75
+ ## Publishing
76
+
77
+ ```bash
78
+ npm login
79
+ npm publish
80
+ ```
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,84 @@
1
+ # omp-mode-switch
2
+
3
+ [![npm version](https://img.shields.io/npm/v/omp-mode-switch)](https://www.npmjs.com/package/omp-mode-switch)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ 一个 OMP 插件,让你在运行中切换三种权限模式。按 **Tab** 键循环切换,或使用 `/mode <ask|auto|plan>` 命令。
7
+
8
+ ---
9
+
10
+ ## 安装
11
+
12
+ ```bash
13
+ omp plugin install omp-mode-switch
14
+ ```
15
+
16
+ 重启 OMP(或新建会话)即可生效。
17
+
18
+ ### 手动安装
19
+
20
+ 将 `mode-switch.ts` 复制到 `~/.omp/agent/extensions/` 或项目的 `.omp/extensions/`。
21
+
22
+ ## 使用方法
23
+
24
+ ### 模式
25
+
26
+ | 模式 | 行为 |
27
+ |--------|------|
28
+ | `ask` | 每个工具调用都需确认(默认) |
29
+ | `auto` | 自动批准所有工具调用 |
30
+ | `plan` | 仅允许只读工具和 `.md` 文件写入,危险 bash 命令被拦截 |
31
+
32
+ ### 切换
33
+
34
+ | 操作 | 效果 |
35
+ |---------------|------|
36
+ | **Tab** | 循环:`ask → auto → plan → ask` |
37
+ | `/mode ask` | 切换到确认模式 |
38
+ | `/mode auto` | 切换到自动模式 |
39
+ | `/mode plan` | 切换到计划模式 |
40
+
41
+ ### 状态指示
42
+
43
+ 当前模式以彩色指示器显示在编辑器底部:
44
+
45
+ - **ASK**(黄色)
46
+ - **AUTO**(绿色)
47
+ - **PLAN**(蓝青色)
48
+
49
+ ## 工作流程示例
50
+
51
+ 1. **探索** — 用 `plan` 模式安全阅读代码
52
+ 2. **规划** — 在 `plan` 模式下编写 `.md` 规划文档
53
+ 3. **执行** — 切换到 `auto` 执行修改
54
+ 4. **审查** — 切换到 `ask` 对关键操作逐次确认
55
+
56
+ 每次新会话自动重置为 `ask` 模式。
57
+
58
+ ## 工作原理
59
+
60
+ - 通过 `pi.registerShortcut()` 注册 Tab 快捷键
61
+ - 通过 `pi.registerCommand()` 注册 `/mode` 命令
62
+ - 拦截 `tool_call` 事件,在 `plan` 模式下阻止破坏性工具
63
+ - 在 `plan` 模式下通过 `pi.setActiveTools()` 限制可用工具
64
+ - 通过 `ctx.ui.setWidget()` 显示彩色状态指示
65
+
66
+ ## 开发
67
+
68
+ ```bash
69
+ git clone https://github.com/your-username/omp-mode-switch.git
70
+ cd omp-mode-switch
71
+ # 修改 mode-switch.ts
72
+ # 复制到 ~/.omp/agent/extensions/ 后重启 OMP 测试
73
+ ```
74
+
75
+ ## 发布
76
+
77
+ ```bash
78
+ npm login
79
+ npm publish
80
+ ```
81
+
82
+ ## 许可证
83
+
84
+ MIT
package/mode-switch.ts ADDED
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Mode Switch - OMP permission mode switching plugin
3
+ *
4
+ * Three modes:
5
+ * ask Prompt for every tool call (default)
6
+ * auto Auto-approve all tool calls
7
+ * plan Read-only mode: only read/search tools + .md writing allowed
8
+ *
9
+ * Shortcut: Tab cycles ask → auto → plan → ask
10
+ * Command: /mode <ask|auto|plan>
11
+ * Display: Colored widget at editor bottom, e.g. [ASK] [AUTO] [PLAN]
12
+ *
13
+ * Install:
14
+ * omp plugin install omp-mode-switch
15
+ * (Restart OMP to activate)
16
+ *
17
+ * Manual install: copy to ~/.omp/agent/extensions/mode-switch.ts
18
+ */
19
+
20
+ import type { ExtensionAPI, ExtensionContext } from "@oh-my-pi/pi-coding-agent";
21
+
22
+ // ─── Types ──────────────────────────────────────────────────────────────────
23
+
24
+ type Mode = "ask" | "auto" | "plan";
25
+
26
+ // ─── Read-only tools allowed in plan mode ───────────────────────────────────
27
+
28
+ const READ_ONLY_TOOLS = [
29
+ "read", "grep", "glob", "search", "ast_grep",
30
+ "codegraph_search", "codegraph_explore", "codegraph_files",
31
+ "codegraph_status", "codegraph_node", "codegraph_callers",
32
+ "codegraph_callees", "codegraph_impact",
33
+ "ls", "find", "head", "tail", "cat", "less",
34
+ ] as const;
35
+
36
+ const roSet = new Set<string>(READ_ONLY_TOOLS);
37
+
38
+ // ─── Bash safety checks ─────────────────────────────────────────────────────
39
+
40
+ const SAFE_BASH_COMMANDS = new Set([
41
+ "cat", "head", "tail", "less", "more", "ls", "find", "grep", "rg",
42
+ "git", "echo", "printf", "pwd", "which", "dirname", "basename",
43
+ "wc", "sort", "uniq", "cut", "date", "uptime", "whoami", "id", "env",
44
+ ]);
45
+
46
+ const DANGEROUS_PATTERNS = [
47
+ " rm ", " rmdir ", " mv ", " cp ", " dd ", " chmod ",
48
+ " chown ", " sudo ", " su ", " &&", " ||", " >", " >>", " |",
49
+ ];
50
+
51
+ function isSafeBash(cmd: string): boolean {
52
+ const t = cmd.trim();
53
+ if (!t) return false;
54
+ for (const p of DANGEROUS_PATTERNS) {
55
+ if (t.includes(p)) return false;
56
+ }
57
+ return SAFE_BASH_COMMANDS.has(t.split(/\s+/)[0]);
58
+ }
59
+
60
+ // ─── Helpers ────────────────────────────────────────────────────────────────
61
+
62
+ function isMdWrite(name: string, input: Record<string, unknown>): boolean {
63
+ if (name !== "write") return false;
64
+ return typeof input.path === "string" && (input.path as string).endsWith(".md");
65
+ }
66
+
67
+ function coloredMode(ctx: ExtensionContext, m: Mode): string {
68
+ const t = ctx.ui.theme;
69
+ if (m === "ask") return t.fg("warning", "ASK");
70
+ if (m === "auto") return t.fg("success", "AUTO");
71
+ return t.fg("accent", "PLAN");
72
+ }
73
+
74
+ // ─── Plugin entry ───────────────────────────────────────────────────────────
75
+
76
+ export default function modeSwitch(pi: ExtensionAPI) {
77
+ let mode: Mode = "ask";
78
+ const CYCLE: Mode[] = ["ask", "auto", "plan"];
79
+
80
+ function showWidget(ctx: ExtensionContext | undefined) {
81
+ if (!ctx) return;
82
+ ctx.ui.setWidget("mode-switch", [coloredMode(ctx, mode)], {
83
+ placement: "belowEditor",
84
+ });
85
+ }
86
+
87
+ function switchTo(next: Mode, ctx: ExtensionContext | undefined) {
88
+ if (mode === next || !ctx) return;
89
+ mode = next;
90
+ showWidget(ctx);
91
+
92
+ if (mode === "plan") {
93
+ pi.setActiveTools([...READ_ONLY_TOOLS, "bash", "write", "edit"]);
94
+ } else {
95
+ pi.setActiveTools(pi.getAllTools());
96
+ }
97
+ }
98
+
99
+ // Tab key to cycle modes
100
+ pi.registerShortcut("Tab", {
101
+ description: "Cycle mode: ask → auto → plan → ask",
102
+ handler: (ctx) => {
103
+ const i = CYCLE.indexOf(mode);
104
+ switchTo(CYCLE[(i + 1) % CYCLE.length], ctx);
105
+ },
106
+ });
107
+
108
+ // /mode command
109
+ pi.registerCommand("mode", {
110
+ description: "Switch permission mode: /mode <ask|auto|plan>",
111
+ getArgumentCompletions: () => ["ask", "auto", "plan"],
112
+ handler: async (args, ctx) => {
113
+ const target = args[0]?.toLowerCase() as Mode | undefined;
114
+ if (target && CYCLE.includes(target)) {
115
+ switchTo(target, ctx);
116
+ }
117
+ },
118
+ });
119
+
120
+ // Plan mode: block non-readonly tools
121
+ pi.on("tool_call", async (event) => {
122
+ if (mode !== "plan") return;
123
+
124
+ const { toolName } = event;
125
+ if (roSet.has(toolName)) return;
126
+
127
+ if (toolName === "bash") {
128
+ const input = (event as Record<string, unknown>).input as Record<string, unknown> | undefined;
129
+ const cmd = input?.command as string | undefined;
130
+ if (cmd && isSafeBash(cmd)) return;
131
+ return { block: true, reason: "Blocked by plan mode: dangerous command" };
132
+ }
133
+
134
+ if ((toolName === "write" || toolName === "edit") && (event as any).input) {
135
+ const input = (event as any).input as Record<string, unknown>;
136
+ if (isMdWrite(toolName, input)) return;
137
+ }
138
+
139
+ return { block: true, reason: "Blocked by plan mode: read-only tools only" };
140
+ });
141
+
142
+ // Reset to ask on new session
143
+ pi.on("session_start", (_event, ctx) => {
144
+ mode = "ask";
145
+ showWidget(ctx);
146
+ pi.setActiveTools(pi.getAllTools());
147
+ });
148
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "omp-mode-switch",
3
+ "version": "1.0.0",
4
+ "description": "OMP plugin: switch between ask / auto / plan permission modes with Tab key",
5
+ "type": "module",
6
+ "main": "mode-switch.ts",
7
+ "scripts": {},
8
+ "files": [
9
+ "mode-switch.ts",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "omp": {
14
+ "name": "Mode Switch",
15
+ "description": "Switch between ask / auto / plan permission modes with Tab key",
16
+ "version": "1.0.0",
17
+ "author": "OMP Community",
18
+ "extensions": {
19
+ "mode-switch": {
20
+ "description": "Mode Switch extension - permission mode toggle",
21
+ "main": "mode-switch.ts"
22
+ }
23
+ }
24
+ },
25
+ "keywords": [
26
+ "omp",
27
+ "plugin",
28
+ "mode",
29
+ "permission",
30
+ "security",
31
+ "ask",
32
+ "auto",
33
+ "plan",
34
+ "oh-my-pi"
35
+ ],
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/your-username/omp-mode-switch.git"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/your-username/omp-mode-switch/issues"
43
+ },
44
+ "homepage": "https://github.com/your-username/omp-mode-switch#readme",
45
+ "engines": {
46
+ "node": ">=18"
47
+ }
48
+ }