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.
Files changed (2) hide show
  1. package/index.js +39 -44
  2. 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
- if (PROMPT_RE.test(clean)) {
65
- store.dispatch({type: 'PICOSH_AI_WAITING', uid, waiting: true});
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
- const {uid} = action;
72
- clearTimeout(timers[uid]);
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 style = props.isAiWaiting ? {
104
- boxShadow: '0 0 8px 2px #4a9eff',
105
- borderRadius: '4px',
106
- animation: 'picosh-glow 1.5s ease-in-out infinite',
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(Tab, props),
113
- props.isAiWaiting && React.createElement('style', {key: 'glow-style'}, `
102
+ waiting && React.createElement('style', {key: 's'}, `
114
103
  @keyframes picosh-glow {
115
- 0%, 100% { opacity: 1; }
116
- 50% { opacity: 0.6; }
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
- // ─── term: image paste + glow wrapper ───────────────────────────────────────
118
+ // ─── image paste (term) ──────────────────────────────────────────────────────
124
119
 
125
120
  exports.decorateTerm = (Term, {React}) => {
126
121
  return class extends React.Component {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picosh",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Hyper plugin: paste clipboard images as file paths",
5
5
  "main": "index.js",
6
6
  "license": "MIT",