pinokiod 3.146.0 → 3.148.0

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/kernel/util.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs')
2
- const { spawn, spawnSync } = require('child_process')
2
+ const { spawn } = require('child_process')
3
3
  const Clipboard = require('copy-paste/promises');
4
4
  const http = require('http');
5
5
  const notifier = require('toasted-notifier');
@@ -12,9 +12,6 @@ const retry = require('async-retry');
12
12
  const child_process = require('node:child_process');
13
13
  const {auto: normalizeEOL} = require("eol");
14
14
  const {EOL} = require("os");
15
- const axios = require('axios');
16
- const { pipeline } = require('stream/promises');
17
- const { pathToFileURL } = require('url');
18
15
  const { randomUUID } = require('crypto');
19
16
  const fsp = fs.promises;
20
17
  const breakPattern = /\n/g;
@@ -114,22 +111,6 @@ function resolvePublicAssetUrl(filePath) {
114
111
  return null
115
112
  }
116
113
 
117
- function soundTargetToClientUrl(target) {
118
- if (!target) {
119
- return null
120
- }
121
- if (target.kind === 'url') {
122
- return target.value
123
- }
124
- if (target.kind === 'file') {
125
- const resolved = resolveAsarPath(path.resolve(target.value))
126
- if (resolved === DEFAULT_CHIME_PATH) {
127
- return DEFAULT_CHIME_URL_PATH
128
- }
129
- return resolvePublicAssetUrl(resolved)
130
- }
131
- return null
132
- }
133
114
  function ensureNotifierBinaries() {
134
115
  if (platform !== 'darwin') {
135
116
  return
@@ -662,146 +643,6 @@ function fill_object(obj, pattern, list, cache) {
662
643
  }
663
644
  const isNonEmptyString = (value) => typeof value === 'string' && value.trim().length > 0
664
645
  const HTTP_URL_REGEX = /^https?:\/\//i
665
- const linuxSoundCandidates = [
666
- { cmd: 'paplay', args: (filePath) => [filePath] },
667
- { cmd: 'aplay', args: (filePath) => [filePath] },
668
- { cmd: 'ffplay', args: (filePath) => ['-autoexit', '-nodisp', filePath] },
669
- { cmd: 'mpg123', args: (filePath) => [filePath] },
670
- { cmd: 'mplayer', args: (filePath) => [filePath] },
671
- { cmd: 'cvlc', args: (filePath) => ['--play-and-exit', filePath] },
672
- ]
673
- let cachedLinuxSoundPlayer
674
- const DEFAULT_CHIME_PATH = resolveAsarPath(path.resolve(__dirname, '../server/public/chime.mp3'))
675
- function pickLinuxSoundPlayer() {
676
- if (cachedLinuxSoundPlayer !== undefined) {
677
- return cachedLinuxSoundPlayer
678
- }
679
- for (const candidate of linuxSoundCandidates) {
680
- try {
681
- const lookup = spawnSync('which', [candidate.cmd], { stdio: 'ignore' })
682
- if (lookup.status === 0) {
683
- cachedLinuxSoundPlayer = candidate
684
- return cachedLinuxSoundPlayer
685
- }
686
- } catch (_) {
687
- // ignore lookup errors and try next candidate
688
- }
689
- }
690
- cachedLinuxSoundPlayer = null
691
- return cachedLinuxSoundPlayer
692
- }
693
- function extractUrlExtension(rawUrl) {
694
- try {
695
- const parsed = new URL(rawUrl)
696
- const ext = path.extname(parsed.pathname)
697
- if (ext && ext.length <= 6) {
698
- return ext
699
- }
700
- } catch (_) {
701
- // ignore URL parse errors
702
- }
703
- return ''
704
- }
705
- async function downloadSoundToTemp(url) {
706
- const tempPath = path.join(os.tmpdir(), `pinokio-notify-${randomUUID()}${extractUrlExtension(url)}`)
707
- const response = await axios.get(url, {
708
- responseType: 'stream',
709
- timeout: 15000,
710
- })
711
- await pipeline(response.data, fs.createWriteStream(tempPath))
712
- return {
713
- filePath: tempPath,
714
- cleanup: async () => {
715
- try {
716
- await fsp.unlink(tempPath)
717
- } catch (_) {
718
- // best-effort cleanup
719
- }
720
- }
721
- }
722
- }
723
- function playSoundFile(filePath) {
724
- if (!filePath) {
725
- return null
726
- }
727
- if (platform === 'darwin') {
728
- return spawn('afplay', [resolveAsarPath(filePath)], { stdio: 'ignore' })
729
- }
730
- if (platform === 'win32') {
731
- const fileUrl = pathToFileURL(resolveAsarPath(filePath)).href.replace(/'/g, "''")
732
- const script = [
733
- "$ErrorActionPreference = 'Stop'",
734
- "Add-Type -AssemblyName presentationCore",
735
- "$player = New-Object system.windows.media.mediaplayer",
736
- `$player.Open([Uri]'${fileUrl}')`,
737
- "$player.Play()",
738
- "while ($player.NaturalDuration.HasTimeSpan -eq $false) { Start-Sleep -Milliseconds 100 }",
739
- "Start-Sleep -Seconds $player.NaturalDuration.TimeSpan.TotalSeconds",
740
- ].join('; ')
741
- return spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-WindowStyle', 'Hidden', '-Command', script], {
742
- stdio: 'ignore'
743
- })
744
- }
745
- const candidate = pickLinuxSoundPlayer()
746
- if (!candidate) {
747
- throw new Error('No supported audio player found for Linux (expected one of paplay, aplay, ffplay, mpg123, mplayer, cvlc).')
748
- }
749
- const preparedPath = resolveAsarPath(filePath)
750
- return spawn(candidate.cmd, candidate.args(preparedPath), { stdio: 'ignore' })
751
- }
752
- function scheduleSoundPlayback(target) {
753
- if (!target) {
754
- return
755
- }
756
- ;(async () => {
757
- let cleanup = null
758
- try {
759
- let filePath
760
- if (target.kind === 'file') {
761
- filePath = resolveAsarPath(target.value)
762
- } else if (target.kind === 'url') {
763
- if (!HTTP_URL_REGEX.test(target.value)) {
764
- throw new Error(`Unsupported sound URL: ${target.value}`)
765
- }
766
- const downloaded = await downloadSoundToTemp(target.value)
767
- filePath = downloaded.filePath
768
- cleanup = downloaded.cleanup
769
- } else {
770
- return
771
- }
772
-
773
- const child = playSoundFile(filePath)
774
- if (!child) {
775
- if (cleanup) {
776
- cleanup().catch(() => {})
777
- }
778
- return
779
- }
780
-
781
- const tidy = () => {
782
- if (!cleanup) {
783
- return
784
- }
785
- cleanup().catch((err) => {
786
- console.error('Failed to clean up temporary sound file:', err)
787
- })
788
- }
789
-
790
- child.once('close', tidy)
791
- child.once('error', tidy)
792
- child.on('error', (err) => {
793
- console.error('Failed to play notification sound:', err)
794
- })
795
- } catch (err) {
796
- if (cleanup) {
797
- cleanup().catch(() => {})
798
- }
799
- console.error('Failed to play notification sound:', err)
800
- }
801
- })().catch((err) => {
802
- console.error('Failed to play notification sound:', err)
803
- })
804
- }
805
646
  function push(params) {
806
647
  /*
807
648
  params :- {
@@ -813,19 +654,21 @@ function push(params) {
813
654
  }
814
655
  */
815
656
  const notifyParams = { ...(params || {}) }
816
- const customSoundTarget = (() => {
817
- if (notifyParams.sound === true) {
818
- return { kind: 'file', value: DEFAULT_CHIME_PATH }
819
- }
820
- if (isNonEmptyString(notifyParams.sound)) {
821
- const trimmed = notifyParams.sound.trim()
822
- if (!trimmed) {
823
- return null
824
- }
825
- return { kind: 'url', value: trimmed }
657
+ const requestedSound = notifyParams.sound
658
+ let clientSoundUrl = null
659
+
660
+ if (requestedSound === true) {
661
+ clientSoundUrl = DEFAULT_CHIME_URL_PATH
662
+ } else if (isNonEmptyString(requestedSound)) {
663
+ const trimmed = requestedSound.trim()
664
+ if (HTTP_URL_REGEX.test(trimmed)) {
665
+ clientSoundUrl = trimmed
666
+ } else {
667
+ console.warn(`Ignoring notification sound (expected http/https URL): ${trimmed}`)
826
668
  }
827
- return null
828
- })()
669
+ }
670
+
671
+ notifyParams.sound = false
829
672
 
830
673
  if (notifyParams.image && !notifyParams.contentImage) {
831
674
  notifyParams.contentImage = notifyParams.image
@@ -854,15 +697,6 @@ function push(params) {
854
697
  notifyParams.appID = WINDOWS_TOAST_APP_ID
855
698
  }
856
699
  }
857
- const clientSoundUrl = soundTargetToClientUrl(customSoundTarget)
858
- if (customSoundTarget) {
859
- notifyParams.sound = false
860
- const shouldPlayLocally = platform !== 'win32' || !clientSoundUrl
861
- if (shouldPlayLocally) {
862
- scheduleSoundPlayback(customSoundTarget)
863
- }
864
- }
865
-
866
700
  const clientImage = resolvePublicAssetUrl(notifyParams.contentImage) || resolvePublicAssetUrl(notifyParams.image)
867
701
  const eventPayload = {
868
702
  id: randomUUID(),
@@ -870,7 +704,7 @@ function push(params) {
870
704
  subtitle: notifyParams.subtitle || null,
871
705
  message: notifyParams.message || '',
872
706
  image: clientImage,
873
- sound: clientSoundUrl,
707
+ sound: clientSoundUrl || null,
874
708
  timestamp: Date.now(),
875
709
  platform,
876
710
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "3.146.0",
3
+ "version": "3.148.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -35,14 +35,14 @@
35
35
  if (!isLast) {
36
36
  const line = this.buffer + segment
37
37
  this.buffer = ""
38
- this.submit(line)
38
+ this.submit(line, { hadLineBreak: true })
39
39
  } else {
40
40
  this.buffer += segment
41
41
  }
42
42
  }
43
43
  }
44
44
 
45
- submit(line) {
45
+ submit(line, meta = {}) {
46
46
  const win = this.getWindow()
47
47
  if (!win || !win.parent || typeof win.parent.postMessage !== "function") {
48
48
  return
@@ -50,11 +50,13 @@
50
50
  const safeLine = (line || "").replace(/[\x00-\x1F\x7F]/g, "")
51
51
  const preview = safeLine.trim()
52
52
  const truncated = preview.length > this.limit ? `${preview.slice(0, this.limit)}...` : preview
53
+ const hadLineBreak = Boolean(meta && meta.hadLineBreak)
54
+ const meaningful = truncated.length > 0 || hadLineBreak
53
55
  win.parent.postMessage({
54
56
  type: "terminal-input",
55
57
  frame: this.getFrameName(),
56
58
  line: truncated,
57
- hasContent: truncated.length > 0
59
+ hasContent: meaningful
58
60
  }, "*")
59
61
  }
60
62
  }
@@ -272,15 +272,15 @@ document.addEventListener("DOMContentLoaded", async () => {
272
272
  if (!isLast) {
273
273
  const line = this.inputBuffer + segment
274
274
  this.inputBuffer = ""
275
- this.notifyLineSubmitted(line)
275
+ this.notifyLineSubmitted(line, { hadLineBreak: true })
276
276
  } else {
277
277
  this.inputBuffer += segment
278
278
  }
279
279
  }
280
280
  }
281
- notifyLineSubmitted(line) {
281
+ notifyLineSubmitted(line, meta = {}) {
282
282
  if (this.inputTracker) {
283
- this.inputTracker.submit(line)
283
+ this.inputTracker.submit(line, meta)
284
284
  return
285
285
  }
286
286
  if (!window || !window.parent || typeof window.parent.postMessage !== "function") {
@@ -290,11 +290,13 @@ document.addEventListener("DOMContentLoaded", async () => {
290
290
  const preview = safeLine.trim()
291
291
  const limit = 200
292
292
  const truncated = preview.length > limit ? preview.slice(0, limit) + "..." : preview
293
+ const hadLineBreak = Boolean(meta && meta.hadLineBreak)
294
+ const meaningful = truncated.length > 0 || hadLineBreak
293
295
  window.parent.postMessage({
294
296
  type: "terminal-input",
295
297
  frame: window.name || null,
296
298
  line: truncated,
297
- hasContent: truncated.length > 0
299
+ hasContent: meaningful
298
300
  }, "*")
299
301
  }
300
302
  write(text) {