@dmsdc-ai/aigentry-deliberation 0.0.34 → 0.0.36
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/README.md +43 -0
- package/clipboard.js +178 -0
- package/index.js +1560 -103
- package/install.js +18 -1
- package/package.json +2 -1
- package/skills/deliberation/SKILL.md +7 -6
- package/skills/deliberation-gate/SKILL.md +9 -5
package/README.md
CHANGED
|
@@ -15,10 +15,14 @@ MCP Deliberation Server — Multi-session AI deliberation with smart speaker ord
|
|
|
15
15
|
- **Browser LLM integration**: CDP-based auto-turn for ChatGPT, Claude, Gemini browser tabs
|
|
16
16
|
- **Chrome Extension support**: Side panel detection via title-based matching
|
|
17
17
|
- **Cross-platform**: macOS (tmux + Terminal.app), Windows (Windows Terminal), Linux
|
|
18
|
+
- **Telepty bus transport**: structured `turn_request` delivery for telepty-managed sessions
|
|
19
|
+
- **User-confirmed speaker selection**: candidates must be confirmed before a session can start
|
|
18
20
|
- **Obsidian archiving**: Auto-archive deliberation results to Obsidian vault
|
|
19
21
|
- **Session monitoring**: Real-time tmux/terminal monitoring
|
|
20
22
|
- **Vote enforcement**: Automatic [AGREE]/[DISAGREE]/[CONDITIONAL] vote marker requirement
|
|
21
23
|
- **Dynamic CLI timeout**: Smart cold-start handling (180s first turn, 120s subsequent)
|
|
24
|
+
- **Split telepty timeouts**: 5s transport ack + 60s semantic response tracking
|
|
25
|
+
- **Typed synthesis envelopes**: validated structured payloads for downstream automation
|
|
22
26
|
- **Runtime logging**: Session lifecycle event logging for observability
|
|
23
27
|
- **Resilient browser automation**: 5-stage degradation state machine with 60s SLO
|
|
24
28
|
- **Model routing**: Dynamic per-provider model selection based on prompt analysis
|
|
@@ -102,6 +106,7 @@ Claude Code, Codex CLI, Gemini CLI의 MCP 설정을 자동 점검하고 문제
|
|
|
102
106
|
| `deliberation_list` | List archived sessions |
|
|
103
107
|
| `deliberation_reset` | Reset session(s) |
|
|
104
108
|
| `deliberation_speaker_candidates` | List available speakers |
|
|
109
|
+
| `deliberation_confirm_speakers` | Confirm the exact user-selected speaker set |
|
|
105
110
|
| `deliberation_browser_llm_tabs` | List browser LLM tabs |
|
|
106
111
|
| `deliberation_browser_auto_turn` | Auto-send turn to browser LLM |
|
|
107
112
|
| `deliberation_route_turn` | Route turn to appropriate transport |
|
|
@@ -109,6 +114,29 @@ Claude Code, Codex CLI, Gemini CLI의 MCP 설정을 자동 점검하고 문제
|
|
|
109
114
|
| `deliberation_cli_auto_turn` | Auto-send turn to CLI speaker |
|
|
110
115
|
| `deliberation_cli_config` | Configure CLI settings |
|
|
111
116
|
|
|
117
|
+
## Start Flow
|
|
118
|
+
|
|
119
|
+
Manual participant selection is enforced for both CLI speakers and telepty sessions.
|
|
120
|
+
|
|
121
|
+
```text
|
|
122
|
+
1. deliberation_speaker_candidates(...)
|
|
123
|
+
2. User picks speakers in the TUI
|
|
124
|
+
3. deliberation_confirm_speakers(selection_token: "<candidate-token>", speakers: [...])
|
|
125
|
+
4. deliberation_start(selection_token: "<confirmed-token>", speakers: [...])
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Raw candidate tokens cannot start a deliberation.
|
|
129
|
+
|
|
130
|
+
## Telepty Transport
|
|
131
|
+
|
|
132
|
+
Telepty-managed sessions are now routed through the telepty bus instead of raw PTY inject guidance.
|
|
133
|
+
|
|
134
|
+
- `deliberation_route_turn` publishes a typed `turn_request` envelope on `ws://localhost:3848/api/bus`
|
|
135
|
+
- transport delivery is tracked with a 5-second `inject_written` ack window
|
|
136
|
+
- semantic completion is tracked with a 60-second self-submit window
|
|
137
|
+
- `session_health` bus events are cached for operator visibility
|
|
138
|
+
- `deliberation_synthesize` validates and emits typed `deliberation_completed` envelopes for downstream automation
|
|
139
|
+
|
|
112
140
|
## Speaker Ordering Strategies
|
|
113
141
|
|
|
114
142
|
| Strategy | Description |
|
|
@@ -179,6 +207,21 @@ cp skills/deliberation-gate/SKILL.md ~/.claude/skills/deliberation-gate/SKILL.md
|
|
|
179
207
|
|
|
180
208
|
## What's New
|
|
181
209
|
|
|
210
|
+
### v0.0.36
|
|
211
|
+
- **README refresh**: clarified the mandatory TUI speaker-selection flow and the confirmed-token handoff before `deliberation_start`
|
|
212
|
+
- **Telepty candidate docs**: documented active telepty session discovery with lightweight `session_id` + `host/pid` locators instead of heavy persisted process snapshots
|
|
213
|
+
- **Cross-project delivery docs**: clarified that active session lookup now resolves across project state directories, which unblocks cross-project `deliberation_respond` flows
|
|
214
|
+
- **Operator guidance**: documented telepty bus transport as the automation path and unmanaged/manual sessions as the fallback path
|
|
215
|
+
|
|
216
|
+
### v0.0.35
|
|
217
|
+
- **Manual selection enforcement**: `deliberation_confirm_speakers` binds a fresh candidate snapshot to the exact user-picked speaker set before `deliberation_start`
|
|
218
|
+
- **Telepty session candidates**: active telepty sessions appear in speaker discovery with lightweight host/pid locators
|
|
219
|
+
- **Cross-project sessions**: session lookup/load/save now resolves active deliberations across project state directories
|
|
220
|
+
- **Telepty bus routing**: telepty speakers route via typed `turn_request` envelopes with 5s transport and 60s semantic timeout tracking
|
|
221
|
+
- **Structured synthesis envelopes**: `deliberation_synthesize` validates typed payloads before telepty bus publication
|
|
222
|
+
- **Codex CLI hardening**: reduced prompt budgets, lower-friction exec profile, and clearer timeout diagnostics
|
|
223
|
+
- **Packaging**: install path now preserves default config and includes required runtime modules (`clipboard.js`, `decision-engine.js`, `i18n.js`)
|
|
224
|
+
|
|
182
225
|
### v0.0.24
|
|
183
226
|
- **Role inference**: Heading marker weight increased from +5 to +8, added critic(검증/평가/Review) and researcher(데이터/Data) patterns to reduce false positives
|
|
184
227
|
- **Logging payload**: TURN log includes `suggested_role`, `role_drift`; CLI_TURN log includes `prior_turns`, `effective_timeout`
|
package/clipboard.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
|
|
2
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
3
|
+
|
|
4
|
+
function commandExistsInPath(command) {
|
|
5
|
+
try {
|
|
6
|
+
const isWin = process.platform === "win32";
|
|
7
|
+
execFileSync(isWin ? "where" : "which", [command], { stdio: "ignore" });
|
|
8
|
+
return true;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function resolveClipboardReader() {
|
|
15
|
+
if (process.platform === "darwin") {
|
|
16
|
+
if (commandExistsInPath("pbpaste")) {
|
|
17
|
+
return { cmd: "pbpaste", args: [] };
|
|
18
|
+
}
|
|
19
|
+
return { cmd: "osascript", args: ["-e", "get the clipboard as «class utf8»"] };
|
|
20
|
+
}
|
|
21
|
+
if (process.platform === "win32") {
|
|
22
|
+
const windowsShell = ["powershell.exe", "powershell", "pwsh.exe", "pwsh"]
|
|
23
|
+
.find(cmd => commandExistsInPath(cmd));
|
|
24
|
+
if (windowsShell) {
|
|
25
|
+
return { cmd: windowsShell, args: ["-NoProfile", "-Command", "Get-Clipboard -Raw"] };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (commandExistsInPath("wl-paste")) {
|
|
29
|
+
return { cmd: "wl-paste", args: ["-n"] };
|
|
30
|
+
}
|
|
31
|
+
if (commandExistsInPath("xclip")) {
|
|
32
|
+
return { cmd: "xclip", args: ["-selection", "clipboard", "-o"] };
|
|
33
|
+
}
|
|
34
|
+
if (commandExistsInPath("xsel")) {
|
|
35
|
+
return { cmd: "xsel", args: ["--clipboard", "--output"] };
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolveClipboardWriter() {
|
|
41
|
+
if (process.platform === "darwin") {
|
|
42
|
+
if (commandExistsInPath("pbcopy")) {
|
|
43
|
+
return { cmd: "pbcopy", args: [] };
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
if (process.platform === "win32") {
|
|
48
|
+
if (commandExistsInPath("clip.exe") || commandExistsInPath("clip")) {
|
|
49
|
+
return { cmd: "clip", args: [] };
|
|
50
|
+
}
|
|
51
|
+
const windowsShell = ["powershell.exe", "powershell", "pwsh.exe", "pwsh"]
|
|
52
|
+
.find(cmd => commandExistsInPath(cmd));
|
|
53
|
+
if (windowsShell) {
|
|
54
|
+
return { cmd: windowsShell, args: ["-NoProfile", "-Command", "[Console]::In.ReadToEnd() | Set-Clipboard"] };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (commandExistsInPath("wl-copy")) {
|
|
58
|
+
return { cmd: "wl-copy", args: [] };
|
|
59
|
+
}
|
|
60
|
+
if (commandExistsInPath("xclip")) {
|
|
61
|
+
return { cmd: "xclip", args: ["-selection", "clipboard"] };
|
|
62
|
+
}
|
|
63
|
+
if (commandExistsInPath("xsel")) {
|
|
64
|
+
return { cmd: "xsel", args: ["--clipboard", "--input"] };
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const COMMON_ENV = {
|
|
70
|
+
LANG: "ko_KR.UTF-8",
|
|
71
|
+
LC_ALL: "ko_KR.UTF-8",
|
|
72
|
+
PATH: process.env.PATH
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function readClipboardText() {
|
|
76
|
+
const tool = resolveClipboardReader();
|
|
77
|
+
if (!tool) {
|
|
78
|
+
throw new Error("No supported clipboard read command found (pbpaste/wl-paste/xclip/xsel etc).");
|
|
79
|
+
}
|
|
80
|
+
const res = spawnSync(tool.cmd, tool.args, {
|
|
81
|
+
encoding: "utf-8",
|
|
82
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
83
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
84
|
+
env: COMMON_ENV,
|
|
85
|
+
timeout: 3000,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (res.error) throw res.error;
|
|
89
|
+
if (res.status !== 0) {
|
|
90
|
+
const err = res.stderr ? res.stderr.toString() : "Unknown error";
|
|
91
|
+
throw new Error(`Clipboard read failed: ${err}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return res.stdout.toString();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function writeClipboardText(text) {
|
|
98
|
+
const tool = resolveClipboardWriter();
|
|
99
|
+
|
|
100
|
+
// AppleScript fallback logic
|
|
101
|
+
const tryAppleScript = (txt) => {
|
|
102
|
+
if (process.platform !== "darwin") return false;
|
|
103
|
+
try {
|
|
104
|
+
const escaped = txt.replace(/["\\]/g, '\\$&');
|
|
105
|
+
const scriptRes = spawnSync("osascript", ["-e", `set the clipboard to "${escaped}"`], { timeout: 3000 });
|
|
106
|
+
return scriptRes.status === 0;
|
|
107
|
+
} catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (!tool) {
|
|
113
|
+
if (tryAppleScript(text)) return;
|
|
114
|
+
throw new Error("No supported clipboard write command found.");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const res = spawnSync(tool.cmd, tool.args, {
|
|
118
|
+
input: text,
|
|
119
|
+
encoding: "utf-8",
|
|
120
|
+
stdio: ["pipe", "ignore", "pipe"],
|
|
121
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
122
|
+
timeout: 3000,
|
|
123
|
+
env: COMMON_ENV
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (res.error || res.status !== 0) {
|
|
127
|
+
if (tryAppleScript(text)) return;
|
|
128
|
+
throw res.error || new Error(`Clipboard write failed with status ${res.status}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Capture current clipboard image to a file (macOS only for now)
|
|
134
|
+
* @param {string} targetPath
|
|
135
|
+
* @returns {boolean} success
|
|
136
|
+
*/
|
|
137
|
+
export function captureClipboardImage(targetPath) {
|
|
138
|
+
if (process.platform !== "darwin") return false;
|
|
139
|
+
|
|
140
|
+
// Using osascript to save PNG data from clipboard
|
|
141
|
+
const script = `
|
|
142
|
+
try
|
|
143
|
+
set theFile to (POSIX file "${targetPath}")
|
|
144
|
+
set theImage to the clipboard as «class PNGf»
|
|
145
|
+
set theOpenFile to open for access theFile with write permission
|
|
146
|
+
set eof theOpenFile to 0
|
|
147
|
+
write theImage to theOpenFile
|
|
148
|
+
close access theOpenFile
|
|
149
|
+
return true
|
|
150
|
+
on error
|
|
151
|
+
try
|
|
152
|
+
close access theFile
|
|
153
|
+
end try
|
|
154
|
+
return false
|
|
155
|
+
end try
|
|
156
|
+
`;
|
|
157
|
+
|
|
158
|
+
const res = spawnSync("osascript", ["-e", script], { timeout: 5000 });
|
|
159
|
+
return res.stdout.toString().trim() === "true";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check if clipboard contains an image
|
|
164
|
+
* @returns {boolean}
|
|
165
|
+
*/
|
|
166
|
+
export function hasClipboardImage() {
|
|
167
|
+
if (process.platform !== "darwin") return false;
|
|
168
|
+
const script = `
|
|
169
|
+
try
|
|
170
|
+
(the clipboard as «class PNGf»)
|
|
171
|
+
return true
|
|
172
|
+
on error
|
|
173
|
+
return false
|
|
174
|
+
end try
|
|
175
|
+
`;
|
|
176
|
+
const res = spawnSync("osascript", ["-e", script], { timeout: 3000 });
|
|
177
|
+
return res.stdout.toString().trim() === "true";
|
|
178
|
+
}
|