cli-jaw 1.0.3 → 1.0.5

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/public/js/ui.ts CHANGED
@@ -93,7 +93,7 @@ export function addMessage(role: string, text: string): HTMLDivElement {
93
93
  const div = document.createElement('div');
94
94
  div.className = `msg msg-${role}`;
95
95
  const rendered = renderMarkdown(text);
96
- div.innerHTML = `<div class="msg-label">${role === 'user' ? t('msg.you') : getAppName()}</div><div class="msg-content">${rendered}</div>`;
96
+ div.innerHTML = `<div class="msg-label">${role === 'user' ? t('msg.you') : getAppName()}</div><div class="msg-content">${rendered}</div><button class="msg-copy" title="Copy"></button>`;
97
97
  container?.appendChild(div);
98
98
  scrollToBottom();
99
99
  return div;
@@ -156,14 +156,15 @@ export async function loadMemory(): Promise<void> {
156
156
  // ── Message copy delegation ──
157
157
  export function initMsgCopy(): void {
158
158
  document.getElementById('chatMessages')?.addEventListener('click', (e) => {
159
- const msgContent = (e.target as HTMLElement)?.closest('.msg-content');
160
- if (!msgContent) return;
161
- // Double-click to copy (not single click)
162
- });
163
- document.getElementById('chatMessages')?.addEventListener('dblclick', (e) => {
164
- const msgContent = (e.target as HTMLElement)?.closest('.msg-content') as HTMLElement | null;
165
- if (!msgContent) return;
166
- const text = msgContent.innerText || msgContent.textContent || '';
167
- navigator.clipboard.writeText(text).catch(() => { });
159
+ const btn = (e.target as HTMLElement)?.closest('.msg-copy') as HTMLElement | null;
160
+ if (!btn) return;
161
+ const msg = btn.closest('.msg');
162
+ const content = msg?.querySelector('.msg-content') as HTMLElement | null;
163
+ if (!content) return;
164
+ const text = content.innerText || content.textContent || '';
165
+ navigator.clipboard.writeText(text).then(() => {
166
+ btn.classList.add('copied');
167
+ setTimeout(() => btn.classList.remove('copied'), 600);
168
+ }).catch(() => { });
168
169
  });
169
170
  }
@@ -6,6 +6,7 @@
6
6
  "cmd.model.desc": "View/change model",
7
7
  "cmd.cli.desc": "View/change active CLI",
8
8
  "cmd.fallback.desc": "Set fallback CLI order",
9
+ "cmd.flush.desc": "View/change flush model",
9
10
  "cmd.version.desc": "Version/CLI install status",
10
11
  "cmd.skill.desc": "Skill list/reset",
11
12
  "cmd.employee.desc": "Reset employees to defaults",
@@ -59,6 +60,11 @@
59
60
  "cmd.arg.browserStatus": "Browser status",
60
61
  "cmd.arg.browserTabs": "Open tabs",
61
62
  "cmd.arg.fallbackOff": "Disable",
63
+ "cmd.arg.flushOff": "Disable (use active CLI)",
64
+ "cmd.flush.current": "🔄 Flush model ({cli}): {model}",
65
+ "cmd.flush.changed": "✅ Flush model changed: {cli} / {model}",
66
+ "cmd.flush.reset": "✅ Flush model reset (using active CLI/model)",
67
+ "cmd.flush.cliUnavailable": "❌ {cli} CLI not found (model: {model}). Please install and retry.",
62
68
  "cmd.arg.argSelect": "Select argument",
63
69
  "api.notCommand": "Not a slash command.",
64
70
  "api.serverError": "Server error: {msg}",
@@ -6,6 +6,7 @@
6
6
  "cmd.model.desc": "모델 확인/변경",
7
7
  "cmd.cli.desc": "활성 CLI 확인/변경",
8
8
  "cmd.fallback.desc": "폴백 CLI 순서 설정",
9
+ "cmd.flush.desc": "Flush 모델 확인/변경",
9
10
  "cmd.version.desc": "버전/CLI 설치 상태",
10
11
  "cmd.skill.desc": "스킬 목록/초기화",
11
12
  "cmd.employee.desc": "직원 기본값 재설정",
@@ -59,6 +60,11 @@
59
60
  "cmd.arg.browserStatus": "브라우저 상태",
60
61
  "cmd.arg.browserTabs": "열린 탭 목록",
61
62
  "cmd.arg.fallbackOff": "비활성화",
63
+ "cmd.arg.flushOff": "비활성화 (active CLI 사용)",
64
+ "cmd.flush.current": "🔄 Flush 모델({cli}): {model}",
65
+ "cmd.flush.changed": "✅ Flush 모델 변경: {cli} / {model}",
66
+ "cmd.flush.reset": "✅ Flush 모델 초기화 (active CLI/모델 사용)",
67
+ "cmd.flush.cliUnavailable": "❌ {cli} CLI를 찾을 수 없습니다 (model: {model}). 설치 후 다시 시도하세요.",
62
68
  "cmd.arg.argSelect": "인자 선택",
63
69
  "api.notCommand": "슬래시 커맨드가 아닙니다.",
64
70
  "api.serverError": "서버 오류: {msg}",
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env bash
2
+ # ═══════════════════════════════════════════════════════════════
3
+ # 🦈 CLI-JAW — WSL One-Click Installer
4
+ # Usage: curl -fsSL https://raw.githubusercontent.com/lidge-jun/cli-jaw/master/scripts/install-wsl.sh | bash
5
+ # ═══════════════════════════════════════════════════════════════
6
+ set -euo pipefail
7
+
8
+ # ── Colors ──
9
+ CYAN='\033[0;36m'
10
+ GREEN='\033[0;32m'
11
+ YELLOW='\033[1;33m'
12
+ RED='\033[0;31m'
13
+ DIM='\033[2m'
14
+ BOLD='\033[1m'
15
+ NC='\033[0m'
16
+
17
+ info() { echo -e "${CYAN}▸${NC} $*"; }
18
+ ok() { echo -e "${GREEN}✔${NC} $*"; }
19
+ warn() { echo -e "${YELLOW}⚠${NC} $*"; }
20
+ fail() { echo -e "${RED}✖${NC} $*"; exit 1; }
21
+
22
+ echo ""
23
+ echo -e "${CYAN}${BOLD}"
24
+ echo " ██████╗██╗ ██╗ ██╗ █████╗ ██╗ ██╗"
25
+ echo " ██╔════╝██║ ██║ ██║██╔══██╗██║ ██║"
26
+ echo " ██║ ██║ ██║█████╗██║███████║██║ █╗ ██║"
27
+ echo " ██║ ██║ ██║╚════╝██║██╔══██║██║███╗██║"
28
+ echo " ╚██████╗███████╗██║ ██║██║ ██║╚███╔███╔╝"
29
+ echo " ╚═════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚══╝╚══╝"
30
+ echo -e "${NC}"
31
+ echo -e "${DIM} WSL One-Click Installer${NC}"
32
+ echo ""
33
+
34
+ NODE_MAJOR=22
35
+
36
+ # ═══════════════════════════════════════
37
+ # Step 1: Node.js version manager
38
+ # ═══════════════════════════════════════
39
+ install_node() {
40
+ # Check if Node.js >= 22 already exists
41
+ if command -v node &>/dev/null; then
42
+ local ver
43
+ ver=$(node -v | sed 's/v//' | cut -d. -f1)
44
+ if [ "$ver" -ge "$NODE_MAJOR" ] 2>/dev/null; then
45
+ ok "Node.js $(node -v) already installed (>= $NODE_MAJOR)"
46
+ return 0
47
+ else
48
+ warn "Node.js $(node -v) found but < $NODE_MAJOR — upgrading..."
49
+ fi
50
+ fi
51
+
52
+ # Prefer fnm (fast, single binary), fall back to nvm if already present
53
+ if command -v fnm &>/dev/null; then
54
+ info "fnm detected — installing Node.js $NODE_MAJOR..."
55
+ fnm install "$NODE_MAJOR" && fnm use "$NODE_MAJOR" && fnm default "$NODE_MAJOR"
56
+ elif command -v nvm &>/dev/null || [ -s "$HOME/.nvm/nvm.sh" ]; then
57
+ info "nvm detected — installing Node.js $NODE_MAJOR..."
58
+ # shellcheck disable=SC1091
59
+ [ -s "$HOME/.nvm/nvm.sh" ] && source "$HOME/.nvm/nvm.sh"
60
+ nvm install "$NODE_MAJOR" && nvm alias default "$NODE_MAJOR"
61
+ else
62
+ info "Installing fnm (Fast Node Manager)..."
63
+ curl -fsSL https://fnm.vercel.app/install | bash
64
+
65
+ # Load fnm into current session
66
+ export PATH="$HOME/.local/share/fnm:$PATH"
67
+ eval "$(fnm env)"
68
+
69
+ info "Installing Node.js $NODE_MAJOR via fnm..."
70
+ fnm install "$NODE_MAJOR" && fnm use "$NODE_MAJOR" && fnm default "$NODE_MAJOR"
71
+ fi
72
+
73
+ # Verify
74
+ if command -v node &>/dev/null; then
75
+ ok "Node.js $(node -v) ready"
76
+ else
77
+ fail "Node.js installation failed. Please install manually: https://nodejs.org"
78
+ fi
79
+ }
80
+
81
+ # ═══════════════════════════════════════
82
+ # Step 2: Install cli-jaw
83
+ # ═══════════════════════════════════════
84
+ install_jaw() {
85
+ if command -v jaw &>/dev/null; then
86
+ ok "cli-jaw already installed ($(jaw --version 2>/dev/null || echo 'unknown version'))"
87
+ info "Updating to latest..."
88
+ npm install -g cli-jaw@latest
89
+ else
90
+ info "Installing cli-jaw globally..."
91
+ npm install -g cli-jaw
92
+ fi
93
+
94
+ ok "cli-jaw installed: $(jaw --version 2>/dev/null || echo 'done')"
95
+ }
96
+
97
+ # ═══════════════════════════════════════
98
+ # Step 3: Doctor check
99
+ # ═══════════════════════════════════════
100
+ run_doctor() {
101
+ info "Running diagnostics..."
102
+ jaw doctor || true
103
+ }
104
+
105
+ # ═══════════════════════════════════════
106
+ # Main
107
+ # ═══════════════════════════════════════
108
+ main() {
109
+ info "Starting CLI-JAW installation on WSL..."
110
+ echo ""
111
+
112
+ install_node
113
+ echo ""
114
+
115
+ install_jaw
116
+ echo ""
117
+
118
+ run_doctor
119
+ echo ""
120
+
121
+ echo -e "${GREEN}${BOLD}═══════════════════════════════════════${NC}"
122
+ echo -e "${GREEN}${BOLD} 🦈 CLI-JAW is ready!${NC}"
123
+ echo -e "${GREEN}${BOLD}═══════════════════════════════════════${NC}"
124
+ echo ""
125
+ echo -e " Run: ${CYAN}jaw serve${NC}"
126
+ echo -e " Open: ${CYAN}http://localhost:3457${NC}"
127
+ echo ""
128
+ echo -e "${DIM} Tip: Authenticate at least one AI engine:${NC}"
129
+ echo -e "${DIM} gh auth login # GitHub Copilot (free)${NC}"
130
+ echo -e "${DIM} claude auth # Anthropic Claude${NC}"
131
+ echo -e "${DIM} codex login # OpenAI Codex${NC}"
132
+ echo ""
133
+ }
134
+
135
+ main "$@"