picosh 0.2.0 → 0.2.2
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 +39 -44
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -44,83 +44,78 @@ 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 = {};
|
|
51
|
+
|
|
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) => {
|
|
60
|
+
if (action.type && action.type.startsWith('SESSION_')) {
|
|
61
|
+
console.log('[picosh] action:', action.type, action.uid ? action.uid.slice(0, 8) : '');
|
|
62
|
+
}
|
|
53
63
|
|
|
54
|
-
exports.middleware = (store) => (next) => (action) => {
|
|
55
64
|
if (action.type === 'SESSION_ADD_DATA') {
|
|
56
65
|
const {uid, data} = action;
|
|
57
66
|
const clean = data.replace(ANSI_RE, '');
|
|
67
|
+
console.log('[picosh] data:', JSON.stringify(clean.slice(-50)));
|
|
58
68
|
|
|
59
69
|
clearTimeout(timers[uid]);
|
|
60
|
-
|
|
61
|
-
store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: false});
|
|
70
|
+
setWaiting(uid, false);
|
|
62
71
|
|
|
63
72
|
timers[uid] = setTimeout(() => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
const matched = PROMPT_RE.test(clean);
|
|
74
|
+
console.log('[picosh] prompt match:', matched);
|
|
75
|
+
if (matched) setWaiting(uid, true);
|
|
67
76
|
}, 500);
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
if (action.type === 'SESSION_PTY_DATA') {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: false});
|
|
80
|
+
clearTimeout(timers[action.uid]);
|
|
81
|
+
setWaiting(action.uid, false);
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
return next(action);
|
|
77
85
|
};
|
|
78
86
|
|
|
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
87
|
exports.decorateTab = (Tab, {React}) => {
|
|
102
88
|
return function PicoshTab(props) {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
const [waiting, setWaitingState] = React.useState(!!waitingState[props.uid]);
|
|
90
|
+
|
|
91
|
+
React.useEffect(() => {
|
|
92
|
+
function onWaiting(e) {
|
|
93
|
+
if (e.detail.uid === props.uid) setWaitingState(e.detail.waiting);
|
|
94
|
+
}
|
|
95
|
+
window.addEventListener('picosh-ai-waiting', onWaiting);
|
|
96
|
+
return () => window.removeEventListener('picosh-ai-waiting', onWaiting);
|
|
97
|
+
}, [props.uid]);
|
|
108
98
|
|
|
109
99
|
return React.createElement(
|
|
110
100
|
'div',
|
|
111
101
|
{style: {position: 'relative', display: 'contents'}},
|
|
112
|
-
React.createElement(
|
|
113
|
-
props.isAiWaiting && React.createElement('style', {key: 'glow-style'}, `
|
|
102
|
+
waiting && React.createElement('style', {key: 's'}, `
|
|
114
103
|
@keyframes picosh-glow {
|
|
115
|
-
0%, 100% {
|
|
116
|
-
50% {
|
|
104
|
+
0%, 100% { box-shadow: 0 0 6px 2px #4a9eff; }
|
|
105
|
+
50% { box-shadow: 0 0 12px 4px #4a9eff; }
|
|
117
106
|
}
|
|
118
107
|
`),
|
|
108
|
+
React.createElement(Tab, Object.assign({}, props, {
|
|
109
|
+
style: Object.assign({}, props.style, waiting ? {
|
|
110
|
+
animation: 'picosh-glow 1.5s ease-in-out infinite',
|
|
111
|
+
borderRadius: '4px',
|
|
112
|
+
} : {}),
|
|
113
|
+
})),
|
|
119
114
|
);
|
|
120
115
|
};
|
|
121
116
|
};
|
|
122
117
|
|
|
123
|
-
// ───
|
|
118
|
+
// ─── image paste (term) ──────────────────────────────────────────────────────
|
|
124
119
|
|
|
125
120
|
exports.decorateTerm = (Term, {React}) => {
|
|
126
121
|
return class extends React.Component {
|