diff --git a/CLAUDE.md b/CLAUDE.md
index af68c2dd..423efe40 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -26,7 +26,7 @@ When user says "COM":
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
-**Version**: 0.1482 (must match `package.json` for npm publish)
+**Version**: 0.1483 (must match `package.json` for npm publish)
## Project Overview
diff --git a/package.json b/package.json
index 948a8d26..a3a0b42d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "claudeman",
- "version": "0.1482",
+ "version": "0.1483",
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
"type": "module",
"main": "dist/index.js",
diff --git a/src/web/public/app.js b/src/web/public/app.js
index 431cd1dd..ae90e4a8 100644
--- a/src/web/public/app.js
+++ b/src/web/public/app.js
@@ -524,17 +524,35 @@ const KeyboardAccessoryBar = {
},
/** Read clipboard and send contents as input */
- async pasteFromClipboard() {
+ /** Show a paste overlay with a textarea for iOS compatibility */
+ pasteFromClipboard() {
if (typeof app === 'undefined' || !app.activeSessionId) return;
- try {
- const text = await navigator.clipboard.readText();
- if (text) {
- app.sendInput(text);
- }
- } catch (_err) {
- // Clipboard API may fail without secure context or permission
- app.showToast?.('Clipboard access denied', 'error');
- }
+
+ // Create overlay
+ const overlay = document.createElement('div');
+ overlay.className = 'paste-overlay';
+ overlay.innerHTML = `
+
+ `;
+
+ const textarea = overlay.querySelector('.paste-textarea');
+ const send = () => {
+ const text = textarea.value;
+ overlay.remove();
+ if (text) app.sendInput(text);
+ };
+ overlay.querySelector('.paste-cancel').addEventListener('click', () => overlay.remove());
+ overlay.querySelector('.paste-send').addEventListener('click', send);
+ overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });
+
+ document.body.appendChild(overlay);
+ textarea.focus();
},
/** Show the accessory bar */
diff --git a/src/web/public/styles.css b/src/web/public/styles.css
index 08baf11d..2069c594 100644
--- a/src/web/public/styles.css
+++ b/src/web/public/styles.css
@@ -8796,6 +8796,73 @@ kbd {
/* Position is handled by JS transform along with toolbar */
}
+ /* Paste overlay for iOS clipboard access */
+ .paste-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.6);
+ z-index: 10000;
+ display: flex;
+ align-items: flex-end;
+ justify-content: center;
+ padding-bottom: env(safe-area-inset-bottom, 12px);
+ }
+
+ .paste-dialog {
+ background: var(--bg-secondary, #1e1e2e);
+ border: 1px solid var(--border-color, #444);
+ border-radius: 12px;
+ padding: 12px;
+ width: calc(100% - 24px);
+ max-width: 400px;
+ margin-bottom: 8px;
+ }
+
+ .paste-textarea {
+ width: 100%;
+ min-height: 100px;
+ background: var(--bg-primary, #0d0d14);
+ color: var(--text-primary, #e0e0e0);
+ border: 1px solid var(--border-color, #444);
+ border-radius: 8px;
+ padding: 10px;
+ font-family: inherit;
+ font-size: 14px;
+ resize: vertical;
+ box-sizing: border-box;
+ }
+
+ .paste-textarea:focus {
+ outline: none;
+ border-color: var(--accent-color, #7aa2f7);
+ }
+
+ .paste-actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 8px;
+ margin-top: 10px;
+ }
+
+ .paste-cancel, .paste-send {
+ padding: 8px 18px;
+ border: none;
+ border-radius: 8px;
+ font-size: 14px;
+ cursor: pointer;
+ }
+
+ .paste-cancel {
+ background: var(--bg-tertiary, #333);
+ color: var(--text-secondary, #aaa);
+ }
+
+ .paste-send {
+ background: var(--accent-color, #7aa2f7);
+ color: #fff;
+ font-weight: 600;
+ }
+
/* LEGACY: Hide old toolbar select (no longer used on mobile) */
.toolbar-select {
display: none !important;