picosh 0.2.0 → 0.2.1
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/index.js +32 -44
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -44,83 +44,71 @@ function downloadImage(url) {
|
|
|
44
44
|
|
|
45
45
|
// ─── AI waiting indicator ───────────────────────────────────────────────────
|
|
46
46
|
|
|
47
|
-
// ANSIエスケープを除去してプロンプト判定
|
|
48
47
|
const ANSI_RE = /\x1b\[[0-9;]*[mGKHF]/g;
|
|
49
|
-
// Claude Code / 一般的なAI CLIのプロンプトパターン
|
|
50
48
|
const PROMPT_RE = />\s*$|❯\s*$/;
|
|
51
|
-
|
|
52
49
|
const timers = {};
|
|
50
|
+
const waitingState = {};
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
function setWaiting(uid, waiting) {
|
|
53
|
+
waitingState[uid] = waiting;
|
|
54
|
+
if (typeof window !== 'undefined') {
|
|
55
|
+
window.dispatchEvent(new CustomEvent('picosh-ai-waiting', {detail: {uid, waiting}}));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
exports.middleware = () => (next) => (action) => {
|
|
55
60
|
if (action.type === 'SESSION_ADD_DATA') {
|
|
56
61
|
const {uid, data} = action;
|
|
57
62
|
const clean = data.replace(ANSI_RE, '');
|
|
58
63
|
|
|
59
64
|
clearTimeout(timers[uid]);
|
|
60
|
-
|
|
61
|
-
store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: false});
|
|
65
|
+
setWaiting(uid, false);
|
|
62
66
|
|
|
63
67
|
timers[uid] = setTimeout(() => {
|
|
64
|
-
if (PROMPT_RE.test(clean))
|
|
65
|
-
store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: true});
|
|
66
|
-
}
|
|
68
|
+
if (PROMPT_RE.test(clean)) setWaiting(uid, true);
|
|
67
69
|
}, 500);
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
if (action.type === 'SESSION_PTY_DATA') {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: false});
|
|
73
|
+
clearTimeout(timers[action.uid]);
|
|
74
|
+
setWaiting(action.uid, false);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
return next(action);
|
|
77
78
|
};
|
|
78
79
|
|
|
79
|
-
exports.reduceUI = (state, action) => {
|
|
80
|
-
if (action.type === 'PICOSH_AI_WAITING') {
|
|
81
|
-
const waiting = state.get('picoshWaiting') || {};
|
|
82
|
-
return state.set('picoshWaiting', {...waiting, [action.uid]: action.waiting});
|
|
83
|
-
}
|
|
84
|
-
return state;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
exports.mapTermsState = (state, map) => {
|
|
88
|
-
return Object.assign(map, {picoshWaiting: state.ui.get('picoshWaiting') || {}});
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
exports.getTabsProps = (parentProps, props) => {
|
|
92
|
-
return Object.assign(props, {picoshWaiting: parentProps.picoshWaiting});
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
exports.getTabProps = (tab, parentProps, props) => {
|
|
96
|
-
return Object.assign(props, {
|
|
97
|
-
isAiWaiting: !!(parentProps.picoshWaiting && parentProps.picoshWaiting[props.uid]),
|
|
98
|
-
});
|
|
99
|
-
};
|
|
100
|
-
|
|
101
80
|
exports.decorateTab = (Tab, {React}) => {
|
|
102
81
|
return function PicoshTab(props) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
82
|
+
const [waiting, setWaitingState] = React.useState(!!waitingState[props.uid]);
|
|
83
|
+
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
function onWaiting(e) {
|
|
86
|
+
if (e.detail.uid === props.uid) setWaitingState(e.detail.waiting);
|
|
87
|
+
}
|
|
88
|
+
window.addEventListener('picosh-ai-waiting', onWaiting);
|
|
89
|
+
return () => window.removeEventListener('picosh-ai-waiting', onWaiting);
|
|
90
|
+
}, [props.uid]);
|
|
108
91
|
|
|
109
92
|
return React.createElement(
|
|
110
93
|
'div',
|
|
111
94
|
{style: {position: 'relative', display: 'contents'}},
|
|
112
|
-
React.createElement(
|
|
113
|
-
props.isAiWaiting && React.createElement('style', {key: 'glow-style'}, `
|
|
95
|
+
waiting && React.createElement('style', {key: 's'}, `
|
|
114
96
|
@keyframes picosh-glow {
|
|
115
|
-
0%, 100% {
|
|
116
|
-
50% {
|
|
97
|
+
0%, 100% { box-shadow: 0 0 6px 2px #4a9eff; }
|
|
98
|
+
50% { box-shadow: 0 0 12px 4px #4a9eff; }
|
|
117
99
|
}
|
|
118
100
|
`),
|
|
101
|
+
React.createElement(Tab, Object.assign({}, props, {
|
|
102
|
+
style: Object.assign({}, props.style, waiting ? {
|
|
103
|
+
animation: 'picosh-glow 1.5s ease-in-out infinite',
|
|
104
|
+
borderRadius: '4px',
|
|
105
|
+
} : {}),
|
|
106
|
+
})),
|
|
119
107
|
);
|
|
120
108
|
};
|
|
121
109
|
};
|
|
122
110
|
|
|
123
|
-
// ───
|
|
111
|
+
// ─── image paste (term) ──────────────────────────────────────────────────────
|
|
124
112
|
|
|
125
113
|
exports.decorateTerm = (Term, {React}) => {
|
|
126
114
|
return class extends React.Component {
|