yt-briefing 1.2.4 → 1.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yt-briefing",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "description": "A self-learning YouTube briefing for Claude Code: it sweeps the channels you follow, filters noise in two stages (title, then transcript), gives you a short briefing of the rest in your language in a pane, and adapts to your ratings — one video at a time.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yt-briefing",
3
- "version": "1.2.4",
3
+ "version": "1.2.5",
4
4
  "description": "The /yt briefing loop as a Claude Code pane: summary, one-key rating, research hand-off.",
5
5
  "author": {
6
6
  "name": "Michal Ryzio"
@@ -172,19 +172,26 @@ const STRAY_TAP_MS = 1500
172
172
 
173
173
  const CHOICES = ['OK', 'Weak', 'Research', 'Stop'] as const
174
174
 
175
- /** The prompt for one briefing: the model sweeps and answers with the summary alone. */
176
- function fetchPrompt(reset: boolean): string {
175
+ /** What a briefing turn must do, read from the system prompt while the loop runs. */
176
+ function loopSection(reset: boolean): string {
177
177
  const sweep = [...engine('yt-sweep'), ...(reset ? ['--reset'] : [])].join(' ')
178
178
  return [
179
- `Next video of my YouTube briefing: run \`${sweep}\`. It prints one JSON line.`,
180
- 'If `status` is `rating_needed`, answer with `summary` verbatim as your whole message, Markdown kept: nothing before or after it, no question, no tool call after it (the rating dialog follows on its own).',
179
+ `The yt-briefing plugin is running the person's YouTube briefing. A user message reading exactly "${NEXT_TEXT}" is its request for the next video:`,
180
+ `run \`${sweep}\`; it prints one JSON line. If \`status\` is \`rating_needed\`, answer with \`summary\` verbatim as your whole message, Markdown kept: nothing before or after it, no question, no tool call after it (the plugin opens the rating dialog itself).`,
181
181
  'Otherwise answer with one short line saying why there is nothing to rate. Write in the language of the summaries.',
182
182
  ].join('\n')
183
183
  }
184
184
 
185
- /** Submit a prompt once the hook that wants it has answered: one submitted from inside would wait on it. */
186
- function submitLater($: EngineInterface, text: string) {
187
- $.clock.after(0, () => void $.prompt.submit({ text }).catch(err => {
185
+ /** What the chat shows of each briefing prompt; the instructions ride along as unseen context. */
186
+ const NEXT_TEXT = 'yt: next video'
187
+
188
+ /** Whether the next briefing prompt starts a fresh sweep. */
189
+ let resetNext = false
190
+
191
+ /** Ask for a briefing once the hook that wants it has answered: one submitted from inside would wait on it. */
192
+ function submitLater($: EngineInterface, reset: boolean) {
193
+ resetNext = reset
194
+ $.clock.after(0, () => void $.prompt.submit({ text: NEXT_TEXT, asUser: true }).catch(err => {
188
195
  looping = false
189
196
  $.ui.toast(`Could not continue the briefing: ${String(err)}`)
190
197
  }))
@@ -232,7 +239,7 @@ async function rateAfterTurn($: EngineInterface) {
232
239
  looping = false
233
240
  return
234
241
  }
235
- submitLater($, fetchPrompt(false))
242
+ submitLater($, false)
236
243
  }
237
244
 
238
245
  export const register: Register = on => {
@@ -255,16 +262,24 @@ export const register: Register = on => {
255
262
  await $.ui.close({ id: PANE })
256
263
  }
257
264
  looping = true
258
- submitLater($, fetchPrompt(true))
265
+ submitLater($, true)
259
266
 
260
267
  return { text: 'No pane here: the briefing runs in the chat.' }
261
268
  })
262
269
 
270
+ // The engine shows a plugin none of its own prompts, so a prompt seen here is the person's.
263
271
  on('prompt.submit', async ($, e, next) => {
264
272
  if (looping && e.origin?.kind !== 'plugin') looping = false
265
273
  return next(e)
266
274
  })
267
275
 
276
+ // The loop's instructions ride in the system prompt, so the chat shows only NEXT_TEXT.
277
+ on('prompt.compose', async ($, e, next) => {
278
+ const composed = await next(e)
279
+ if (!looping) return composed
280
+ return { sections: [...composed.sections, { id: 'yt-briefing:loop', text: loopSection(resetNext), scope: 'session' as const }] }
281
+ })
282
+
268
283
  on('turn.complete', async ($, e, next) => {
269
284
  if (looping && !e.agentId && e.reason === 'answer') void rateAfterTurn($)
270
285
  return next(e)