@tuzelko/opencode-delayed-message 0.1.5 → 0.1.6
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/README.md +8 -7
- package/gui-experimental.cjs +9 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,15 +82,16 @@ Treat this as a prompt-level guarantee, not encryption.
|
|
|
82
82
|
Above the composer, while a message is pending:
|
|
83
83
|
|
|
84
84
|
```text
|
|
85
|
-
⏰
|
|
85
|
+
⏰ Delayed
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
The label is constant — the list behind it carries the times and the count.
|
|
89
|
+
Click it for one line per message with the scheduled time, a preview, and the
|
|
90
|
+
countdown, like the app's own subagent list. `✎` to edit and `×` to cancel appear
|
|
91
|
+
when you hover a row. Edit cancels the pending job and puts the whole command back
|
|
92
|
+
into the composer — `/delayed-message`, the scheduled time, and the full text —
|
|
93
|
+
with the cursor in the prompt. Adjust anything and submit to reschedule. The pill
|
|
94
|
+
disappears when the message is delivered or cancelled.
|
|
94
95
|
|
|
95
96
|
The terminal UI has no pill — there the transcript note is the only trace.
|
|
96
97
|
|
package/gui-experimental.cjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require("solid-js/web"),t=require("solid-js"),n=require("effect"),r=require("@opencode/plugin/gui");var i=require("@opencode/plugin/rpc").Rpc.define({id:`delayed-message`,methods:{pending:{input:{type:`object`,properties:{sessionID:{type:`string`}},required:[`sessionID`],additionalProperties:!1},output:{type:`object`,properties:{jobs:{type:`array`,items:{type:`object`,properties:{id:{type:`string`},fireAt:{type:`number`},preview:{type:`string`}},required:[`id`,`fireAt`,`preview`],additionalProperties:!1}}},required:[`jobs`],additionalProperties:!1}},cancel:{input:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`}},required:[`sessionID`,`id`],additionalProperties:!1},output:{type:`object`,properties:{ok:{type:`boolean`}},required:[`ok`],additionalProperties:!1}},deliver:{input:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`}},required:[`sessionID`,`id`],additionalProperties:!1},output:{type:`object`,properties:{status:{type:`string`}},required:[`status`],additionalProperties:!1}},edit:{input:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`}},required:[`sessionID`,`id`],additionalProperties:!1},output:{type:`object`,properties:{ok:{type:`boolean`},text:{type:`string`},fireAt:{type:`number`}},required:[`ok`],additionalProperties:!1}}},events:{scheduled:{schema:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`},fireAt:{type:`number`},preview:{type:`string`},directory:{type:`string`}},required:[`sessionID`,`id`,`fireAt`,`preview`,`directory`],additionalProperties:!1}},fired:{schema:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`}},required:[`sessionID`,`id`],additionalProperties:!1}},cancelled:{schema:{type:`object`,properties:{sessionID:{type:`string`},id:{type:`string`}},required:[`sessionID`,`id`],additionalProperties:!1}}}}),a=(0,e.template)(`<div class=dm tabindex=0>`),o=(0,e.template)(`<div class=dm-row><span class=dm-time></span><span class=dm-text></span><span class=dm-left></span><span class=dm-actions><button class=dm-action>✎</button><button class=dm-action>×`),s=2**31-1,c=e=>String(e).padStart(2,`0`),l=e=>{let t=new Date(e),n=`${t.getFullYear()}-${c(t.getMonth()+1)}-${c(t.getDate())}`,r=`${c(t.getHours())}:${c(t.getMinutes())}`;return t.getSeconds()===0?`${n}T${r}`:`${n}T${r}:${c(t.getSeconds())}`},u=`
|
|
2
2
|
[data-slot="session-plugin-pill-popover"]:has(.dm) > div:first-child { display: none; }
|
|
3
|
-
.dm { display: flex; flex-direction: column; gap: 1px;
|
|
3
|
+
.dm { display: flex; flex-direction: column; gap: 1px; }
|
|
4
4
|
.dm:focus { outline: none; }
|
|
5
|
-
.dm-row { position: relative; display: flex; align-items: center; gap: 8px; padding:
|
|
6
|
-
.dm-row:hover { background:
|
|
7
|
-
.dm-time { flex: none; font-weight:
|
|
8
|
-
.dm-text { flex: 1 1 auto; min-width: 0;
|
|
9
|
-
.dm-left { flex: none; min-width: 52px; text-align: right;
|
|
5
|
+
.dm-row { position: relative; display: flex; align-items: center; gap: 8px; height: 28px; padding: 0 6px 0 12px; border-radius: 4px; font-size: 13px; font-weight: 440; line-height: var(--line-height-compact); letter-spacing: -.04px; }
|
|
6
|
+
.dm-row:hover { background: var(--v2-overlay-simple-overlay-hover); }
|
|
7
|
+
.dm-time { flex: none; font-weight: 530; font-variant-numeric: tabular-nums; }
|
|
8
|
+
.dm-text { flex: 1 1 auto; min-width: 0; color: var(--v2-text-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
9
|
+
.dm-left { flex: none; min-width: 52px; text-align: right; color: var(--v2-text-text-muted); font-size: 11px; font-weight: 440; letter-spacing: .05px; font-variant-numeric: tabular-nums; white-space: nowrap; transition: opacity .12s ease; }
|
|
10
10
|
.dm-actions { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: flex; gap: 2px; opacity: 0; pointer-events: none; transition: opacity .12s ease; }
|
|
11
11
|
.dm-row:hover .dm-left, .dm-row:has(.dm-action:focus-visible) .dm-left { opacity: 0; }
|
|
12
12
|
.dm-row:hover .dm-actions, .dm-row:has(.dm-action:focus-visible) .dm-actions { opacity: 1; pointer-events: auto; }
|
|
13
|
-
.dm-action { flex: none; width:
|
|
14
|
-
.dm-action:hover { opacity: 1; background:
|
|
15
|
-
`,d=r.Plugin.define({i18n:{en:{"pill.
|
|
13
|
+
.dm-action { flex: none; width: 22px; height: 22px; border: 0; border-radius: 4px; background: transparent; color: inherit; opacity: .55; cursor: pointer; font: inherit; line-height: 1; }
|
|
14
|
+
.dm-action:hover { opacity: 1; background: var(--v2-overlay-simple-overlay-hover); }
|
|
15
|
+
`,d=r.Plugin.define({i18n:{en:{"pill.label":`Delayed`,"menu.title":`Scheduled messages`,"row.cancel":`Cancel`,"row.edit":`Edit`,"left.now":`now`,"left.days":`{{days}}d {{hours}}h`,"left.hours":`{{hours}}h {{minutes}}m`,"left.minutes":`{{minutes}}m`},ru:{"pill.label":`Отложенное`,"menu.title":`Отложенные сообщения`,"row.cancel":`Отменить`,"row.edit":`Изменить`,"left.now":`сейчас`,"left.days":`{{days}} д {{hours}} ч`,"left.hours":`{{hours}} ч {{minutes}} мин`,"left.minutes":`{{minutes}} мин`},de:{"pill.label":`Geplant`,"menu.title":`Geplante Nachrichten`,"row.cancel":`Abbrechen`,"row.edit":`Bearbeiten`,"left.now":`jetzt`,"left.days":`{{days}} T {{hours}} Std.`,"left.hours":`{{hours}} Std. {{minutes}} Min.`,"left.minutes":`{{minutes}} Min.`},fr:{"pill.label":`Programmé`,"menu.title":`Messages programmés`,"row.cancel":`Annuler`,"row.edit":`Modifier`,"left.now":`maintenant`,"left.days":`{{days}} j {{hours}} h`,"left.hours":`{{hours}} h {{minutes}} min`,"left.minutes":`{{minutes}} min`},zh:{"pill.label":`已安排`,"menu.title":`已安排的消息`,"row.cancel":`取消`,"row.edit":`编辑`,"left.now":`现在`,"left.days":`{{days}} 天 {{hours}} 小时`,"left.hours":`{{hours}} 小时 {{minutes}} 分钟`,"left.minutes":`{{minutes}} 分钟`}},setup(n){let[s,c]=(0,t.createSignal)({}),d=(e,t)=>c(n=>({...n,[e]:[...(n[e]??[]).filter(e=>e.id!==t.id),t].sort((e,t)=>e.fireAt-t.fireAt)})),f=(e,t)=>c(n=>({...n,[e]:(n[e]??[]).filter(e=>e.id!==t)})),p=e=>new Date(e).toLocaleTimeString(n.locale.locale(),{hour:`2-digit`,minute:`2-digit`}),m=e=>new Date(e).toLocaleDateString(n.locale.locale(),{day:`2-digit`,month:`2-digit`}),h=e=>{let t=new Date(e),n=new Date,r=p(e);return t.toDateString()===n.toDateString()?r:`${m(e)} ${r}`},g=e=>{let t=e-Date.now();if(t<=0)return n.t(`left.now`);let r=Math.ceil(t/6e4),i=Math.floor(r/60),a=Math.floor(i/24);return a>0?n.t(`left.days`,{days:a,hours:i%24}):i>0?n.t(`left.hours`,{hours:i,minutes:r%60}):n.t(`left.minutes`,{minutes:r})},_=n.client.rpc(i);_.events.on(`scheduled`,e=>{d(e.data.sessionID,{id:e.data.id,fireAt:e.data.fireAt,preview:e.data.preview})}),_.events.on(`fired`,e=>{f(e.data.sessionID,e.data.id)}),_.events.on(`cancelled`,e=>{f(e.data.sessionID,e.data.id)});let v=async(e,t)=>{try{let{ok:n}=await _.cancel({sessionID:e,id:t});n&&f(e,t)}catch{}};(0,r.createKeyed)(()=>n.sessions.current()?.id,e=>{_.pending({sessionID:e}).then(({jobs:t})=>c(n=>({...n,[e]:t}))).catch(()=>{})}),n.add(r.Style,u),n.add(r.ComposerPill,{id:`pending`,show(e){if((s()[e.session.id]??[]).length!==0)return{label:n.t(`pill.label`),icon:`notifications`,title:n.t(`menu.title`)}},menu:r=>(()=>{var i=a();return(0,e.insert)(i,(0,e.createComponent)(t.For,{get each(){return s()[r.session.id]??[]},children:t=>(()=>{var i=o(),a=i.firstChild,s=a.nextSibling,c=s.nextSibling,u=c.nextSibling.firstChild,d=u.nextSibling;return(0,e.insert)(a,()=>h(t.fireAt)),(0,e.insert)(s,()=>t.preview),(0,e.insert)(c,()=>g(t.fireAt)),u.$$click=()=>{_.edit({sessionID:r.session.id,id:t.id}).then(({ok:e,text:n,fireAt:i})=>{e&&n!==void 0&&i!==void 0&&(f(r.session.id,t.id),r.screen.composer.setText(`/delayed-message ${l(i)} ${n}`),r.close(),r.screen.composer.focus())}).catch(()=>{})},d.$$click=()=>void v(r.session.id,t.id),(0,e.effect)(t=>{var r=n.t(`row.edit`),i=n.t(`row.edit`),a=n.t(`row.cancel`),o=n.t(`row.cancel`);return r!==t.e&&(0,e.setAttribute)(u,`title`,t.e=r),i!==t.t&&(0,e.setAttribute)(u,`aria-label`,t.t=i),a!==t.a&&(0,e.setAttribute)(d,`title`,t.a=a),o!==t.o&&(0,e.setAttribute)(d,`aria-label`,t.o=o),t},{e:void 0,t:void 0,a:void 0,o:void 0}),i})()})),i})()})},main(e){let t=n.Schema.Struct({id:n.Schema.String,sessionID:n.Schema.String,directory:n.Schema.String,fireAt:n.Schema.Number}),r=e.storage.store(`pending`,{schema:n.Schema.Array(t),initial:[]}),a=new Map,o=new Map,c=e=>{let t=a.get(e);t&&clearTimeout(t),a.delete(e)},l=e=>{c(e),o.delete(e),r.value.some(t=>t.id===e)&&r.set(r.value.filter(t=>t.id!==e))},u=e=>{c(e.id);let t=e.fireAt-Date.now();t>s-1?a.set(e.id,setTimeout(()=>u(e),s-1)):a.set(e.id,setTimeout(()=>void d(e),Math.max(0,t)))},d=async t=>{if(c(t.id),Date.now()<t.fireAt)u(t);else try{let{status:n}=await e.client.rpc(i).deliver({sessionID:t.sessionID,id:t.id},{location:{directory:t.directory}});if(n===`delivered`||n===`missing`){o.delete(t.id),l(t.id);return}if(n===`failed`){let e=(o.get(t.id)??0)+1;if(e>=5){o.delete(t.id),l(t.id);return}o.set(t.id,e)}a.set(t.id,setTimeout(()=>void d(t),n===`busy`?2e3:3e4))}catch{a.set(t.id,setTimeout(()=>void d(t),15e3))}},f=e=>{r.set([...r.value.filter(t=>t.id!==e.id),e]),u(e)},p=e=>{if(e.type===`rpc.delayed-message.scheduled`){let t=e.data;if(!t?.id||!t.sessionID||!t.fireAt||!t.directory)return;f({id:t.id,sessionID:t.sessionID,directory:t.directory,fireAt:t.fireAt})}else if(e.type===`rpc.delayed-message.fired`||e.type===`rpc.delayed-message.cancelled`){let t=e.data;t?.id&&l(t.id)}};for(let e of r.value)u(e);(async()=>{for(;!e.signal.aborted;){try{for await(let t of e.client.event.subscribe({signal:e.signal}))p(t)}catch{}if(e.signal.aborted)break;await new Promise(e=>setTimeout(e,3e3))}})(),e.onCleanup(()=>{for(let e of a.values())clearTimeout(e);a.clear()})}});(0,e.delegateEvents)([`click`]),exports.default=d;
|