pinokiod 8.0.8 → 8.0.10

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.
@@ -6973,3 +6973,68 @@ body.dark .swal2-popup.swal2-modal:not(.loader-popup):not(.pinokio-download-moda
6973
6973
  width: 100%;
6974
6974
  }
6975
6975
  }
6976
+
6977
+ .pinokio-path-blocker > p {
6978
+ margin: 0 0 14px;
6979
+ }
6980
+
6981
+ .pinokio-path-blocker-list {
6982
+ margin: 0 0 14px;
6983
+ padding: 0;
6984
+ list-style: none;
6985
+ }
6986
+
6987
+ .pinokio-path-blocker-item {
6988
+ display: flex;
6989
+ align-items: baseline;
6990
+ justify-content: space-between;
6991
+ gap: 16px;
6992
+ padding: 8px 0;
6993
+ border-bottom: 1px solid rgba(127, 127, 127, 0.18);
6994
+ }
6995
+
6996
+ .pinokio-path-blocker-name {
6997
+ font-weight: 600;
6998
+ }
6999
+
7000
+ .pinokio-path-blocker-detail {
7001
+ font-size: 12px;
7002
+ overflow-wrap: anywhere;
7003
+ text-align: right;
7004
+ }
7005
+
7006
+ .pinokio-path-blocker-files {
7007
+ margin: 0 0 14px;
7008
+ }
7009
+
7010
+ .pinokio-path-blocker-files summary {
7011
+ cursor: pointer;
7012
+ }
7013
+
7014
+ .pinokio-path-blocker-files div {
7015
+ display: grid;
7016
+ gap: 6px;
7017
+ margin-top: 8px;
7018
+ }
7019
+
7020
+ .pinokio-path-blocker-files code {
7021
+ overflow-wrap: anywhere;
7022
+ white-space: normal;
7023
+ }
7024
+
7025
+ .pinokio-path-blocker-wait {
7026
+ display: flex;
7027
+ align-items: center;
7028
+ gap: 8px;
7029
+ }
7030
+
7031
+ @media (max-width: 560px) {
7032
+ .pinokio-path-blocker-item {
7033
+ display: grid;
7034
+ gap: 2px;
7035
+ }
7036
+
7037
+ .pinokio-path-blocker-detail {
7038
+ text-align: left;
7039
+ }
7040
+ }
@@ -11866,15 +11866,13 @@ const rerenderMenuSection = (container, html) => {
11866
11866
  actions: "hidden"
11867
11867
  }
11868
11868
  });
11869
- let res = await fetch("/pinokio/delete", {
11869
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
11870
11870
  method: "post",
11871
11871
  headers: {
11872
11872
  "Content-Type": "application/json"
11873
11873
  },
11874
11874
  body: JSON.stringify({ name })
11875
- }).then((res) => {
11876
- return res.json()
11877
- })
11875
+ }))
11878
11876
  console.log("res", res)
11879
11877
  Swal.close()
11880
11878
  if (res) {
@@ -231,18 +231,18 @@ document.addEventListener("DOMContentLoaded", async () => {
231
231
  if (proceed) {
232
232
  document.querySelector(".reset-bin-loading").classList.remove("hidden")
233
233
  document.querySelector("#del-bin").classList.add("hidden")
234
- let res = await fetch("/pinokio/delete", {
234
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
235
235
  method: "post",
236
236
  headers: {
237
237
  "Content-Type": "application/json"
238
238
  },
239
239
  body: JSON.stringify({ type: "bin" })
240
- }).then((res) => {
241
- return res.json()
242
- })
240
+ }))
243
241
  console.log(res)
244
242
  document.querySelector(".reset-bin-loading").classList.add("hidden")
245
- if (res.error) {
243
+ if (res.cancelled) {
244
+ document.querySelector("#del-bin").classList.remove("hidden")
245
+ } else if (res.error) {
246
246
  alert(res.error)
247
247
  } else {
248
248
  //location.href = location.href
@@ -940,18 +940,18 @@ document.addEventListener("DOMContentLoaded", async () => {
940
940
  if (proceed) {
941
941
  document.querySelector(".reset-bin-loading").classList.remove("hidden")
942
942
  document.querySelector("#del-bin").classList.add("hidden")
943
- let res = await fetch("/pinokio/delete", {
943
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
944
944
  method: "post",
945
945
  headers: {
946
946
  "Content-Type": "application/json"
947
947
  },
948
948
  body: JSON.stringify({ type: "bin" })
949
- }).then((res) => {
950
- return res.json()
951
- })
949
+ }))
952
950
  console.log(res)
953
951
  document.querySelector(".reset-bin-loading").classList.add("hidden")
954
- if (res.error) {
952
+ if (res.cancelled) {
953
+ document.querySelector("#del-bin").classList.remove("hidden")
954
+ } else if (res.error) {
955
955
  alert(res.error)
956
956
  } else {
957
957
  document.querySelector("#install-form").submit()
@@ -447,16 +447,18 @@ document.addEventListener("DOMContentLoaded", async () => {
447
447
  }
448
448
  })
449
449
  try {
450
- const res = await fetch("/pinokio/delete", {
450
+ const res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
451
451
  method: "post",
452
452
  headers: {
453
453
  "Content-Type": "application/json"
454
454
  },
455
455
  body: JSON.stringify({ name: projectName })
456
- }).then((response) => response.json())
456
+ }))
457
457
  Swal.close()
458
458
  if (res && res.success) {
459
459
  navigateHome()
460
+ } else if (res && res.cancelled) {
461
+ return
460
462
  } else if (res && res.error) {
461
463
  alert(res.error)
462
464
  } else {
@@ -636,15 +636,13 @@ document.addEventListener("click", async (e) => {
636
636
  actions: "hidden"
637
637
  }
638
638
  });
639
- let res = await fetch("/pinokio/delete", {
639
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
640
640
  method: "post",
641
641
  headers: {
642
642
  "Content-Type": "application/json"
643
643
  },
644
644
  body: JSON.stringify({ name })
645
- }).then((res) => {
646
- return res.json()
647
- })
645
+ }))
648
646
  console.log("res", res)
649
647
  Swal.close()
650
648
  if (res) {
@@ -4031,15 +4031,13 @@ document.addEventListener("click", async (e) => {
4031
4031
  actions: "hidden"
4032
4032
  }
4033
4033
  });
4034
- let res = await fetch("/pinokio/delete", {
4034
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
4035
4035
  method: "post",
4036
4036
  headers: {
4037
4037
  "Content-Type": "application/json"
4038
4038
  },
4039
4039
  body: JSON.stringify({ name })
4040
- }).then((res) => {
4041
- return res.json()
4042
- })
4040
+ }))
4043
4041
  console.log("res", res)
4044
4042
  Swal.close()
4045
4043
  if (res) {
@@ -851,6 +851,31 @@ document.addEventListener("DOMContentLoaded", async () => {
851
851
  socket.close()
852
852
  } else if (packet.type === "result") {
853
853
  resolve()
854
+ } else if (packet.type === "path.remove.blocked") {
855
+ const result = await PinokioPathRemoval.show({
856
+ details: packet.data,
857
+ retry: async () => {
858
+ const response = await fetch("/pinokio/delete", {
859
+ method: "post",
860
+ headers: {
861
+ "Content-Type": "application/json"
862
+ },
863
+ body: JSON.stringify({ type: "conda-runtime" })
864
+ })
865
+ const payload = await response.json()
866
+ const blocked = PinokioPathRemoval.blockedDetails(payload)
867
+ if (!blocked && (!response.ok || (payload && payload.error))) {
868
+ const message = payload && payload.error
869
+ throw new Error(typeof message === "string" ? message : `Cleanup failed (${response.status})`)
870
+ }
871
+ return payload
872
+ }
873
+ })
874
+ if (result && result.success) {
875
+ setTimeout(() => window.location.reload(), 0)
876
+ } else if (result && result.cancelled) {
877
+ navigateToCallback()
878
+ }
854
879
  } else if (packet.type === "error") {
855
880
  if (typeof packet.data === "string" && packet.data.includes("__PINOKIO_BLOCKER__")) {
856
881
  return
@@ -2361,15 +2361,13 @@ document.addEventListener("click", async (e) => {
2361
2361
  actions: "hidden"
2362
2362
  }
2363
2363
  });
2364
- let res = await fetch("/pinokio/delete", {
2364
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
2365
2365
  method: "post",
2366
2366
  headers: {
2367
2367
  "Content-Type": "application/json"
2368
2368
  },
2369
2369
  body: JSON.stringify({ name })
2370
- }).then((res) => {
2371
- return res.json()
2372
- })
2370
+ }))
2373
2371
  console.log("res", res)
2374
2372
  Swal.close()
2375
2373
  if (res) {
@@ -1537,18 +1537,18 @@ document.addEventListener("DOMContentLoaded", async () => {
1537
1537
  if (proceed) {
1538
1538
  document.querySelector(".reset-bin-loading").classList.remove("hidden")
1539
1539
  document.querySelector("#del-bin").classList.add("hidden")
1540
- let res = await fetch("/pinokio/delete", {
1540
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
1541
1541
  method: "post",
1542
1542
  headers: {
1543
1543
  "Content-Type": "application/json"
1544
1544
  },
1545
1545
  body: JSON.stringify({ type: "bin" })
1546
- }).then((res) => {
1547
- return res.json()
1548
- })
1546
+ }))
1549
1547
  console.log(res)
1550
1548
  document.querySelector(".reset-bin-loading").classList.add("hidden")
1551
- if (res.error) {
1549
+ if (res.cancelled) {
1550
+ document.querySelector("#del-bin").classList.remove("hidden")
1551
+ } else if (res.error) {
1552
1552
  alert(res.error)
1553
1553
  } else {
1554
1554
  location.href = location.href
@@ -1561,18 +1561,18 @@ document.addEventListener("DOMContentLoaded", async () => {
1561
1561
  if (proceed) {
1562
1562
  document.querySelector(".reset-cache-loading").classList.remove("hidden")
1563
1563
  document.querySelector("#del-cache").classList.add("hidden")
1564
- let res = await fetch("/pinokio/delete", {
1564
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
1565
1565
  method: "post",
1566
1566
  headers: {
1567
1567
  "Content-Type": "application/json"
1568
1568
  },
1569
1569
  body: JSON.stringify({ type: "cache" })
1570
- }).then((res) => {
1571
- return res.json()
1572
- })
1570
+ }))
1573
1571
  console.log(res)
1574
1572
  document.querySelector(".reset-cache-loading").classList.add("hidden")
1575
- if (res.error) {
1573
+ if (res.cancelled) {
1574
+ document.querySelector("#del-cache").classList.remove("hidden")
1575
+ } else if (res.error) {
1576
1576
  alert(res.error)
1577
1577
  } else {
1578
1578
  location.href = location.href
@@ -389,17 +389,17 @@
389
389
  if (proceed) {
390
390
  document.querySelector(".reset-bin-loading").classList.remove("hidden")
391
391
  document.querySelector("#del-bin").classList.add("hidden")
392
- let res = await fetch("/pinokio/delete", {
392
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
393
393
  method: "post",
394
394
  headers: {
395
395
  "Content-Type": "application/json"
396
396
  },
397
397
  body: JSON.stringify({ type: "bin" })
398
- }).then((res) => {
399
- return res.json()
400
- })
398
+ }))
401
399
  document.querySelector(".reset-bin-loading").classList.add("hidden")
402
- if (res.error) {
400
+ if (res.cancelled) {
401
+ document.querySelector("#del-bin").classList.remove("hidden")
402
+ } else if (res.error) {
403
403
  alert(res.error)
404
404
  } else {
405
405
  document.querySelector("#install-form").submit()
@@ -3339,18 +3339,18 @@ document.addEventListener("DOMContentLoaded", async () => {
3339
3339
  if (proceed) {
3340
3340
  document.querySelector(".reset-bin-loading").classList.remove("hidden")
3341
3341
  document.querySelector("#del-bin").classList.add("hidden")
3342
- let res = await fetch("/pinokio/delete", {
3342
+ let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
3343
3343
  method: "post",
3344
3344
  headers: {
3345
3345
  "Content-Type": "application/json"
3346
3346
  },
3347
3347
  body: JSON.stringify({ type: "bin" })
3348
- }).then((res) => {
3349
- return res.json()
3350
- })
3348
+ }))
3351
3349
  console.log(res)
3352
3350
  document.querySelector(".reset-bin-loading").classList.add("hidden")
3353
- if (res.error) {
3351
+ if (res.cancelled) {
3352
+ document.querySelector("#del-bin").classList.remove("hidden")
3353
+ } else if (res.error) {
3354
3354
  alert(res.error)
3355
3355
  } else {
3356
3356
  //location.href = location.href
@@ -262,7 +262,7 @@ test('Conda install replaces the stale runtime and rebuilds declared Conda modul
262
262
  )
263
263
  })
264
264
 
265
- test('Conda replacement stops, preserves, and restarts a running managed Caddy', async () => {
265
+ test('Conda replacement stops a running managed Caddy without restoring it', async () => {
266
266
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-caddy-lifecycle-'))
267
267
  await createMiniforge(root)
268
268
  const kernel = createKernel(root, 'win32')
@@ -277,10 +277,6 @@ test('Conda replacement stops, preserves, and restarts a running managed Caddy',
277
277
  events.push('caddy-stop')
278
278
  caddyRunning = false
279
279
  },
280
- start: async () => {
281
- events.push('caddy-start')
282
- caddyRunning = true
283
- },
284
280
  }
285
281
  kernel.bin.installed.conda = new Set(['caddy'])
286
282
  kernel.bin.mod = { caddy }
@@ -311,9 +307,8 @@ test('Conda replacement stops, preserves, and restarts a running managed Caddy',
311
307
 
312
308
  assert.ok(events.indexOf('caddy-stop') < events.indexOf('remove-miniforge'))
313
309
  assert.ok(events.indexOf('remove-miniforge') < events.indexOf('bootstrap'))
314
- assert.ok(events.indexOf('conda-install') < events.indexOf('caddy-start'))
315
- assert.match(condaInstall.message[1], / caddy=2\.9\.1$/)
316
- assert.equal(caddyRunning, true)
310
+ assert.doesNotMatch(condaInstall.message[1], /caddy=/)
311
+ assert.equal(caddyRunning, false)
317
312
  })
318
313
 
319
314
  test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
@@ -452,7 +447,7 @@ test('Conda install propagates bootstrap failure after replacing the runtime', a
452
447
  )
453
448
  })
454
449
 
455
- test('Conda install reports manual recovery when the old runtime cannot be removed', async () => {
450
+ test('Conda install reports recovery details when the old runtime cannot be removed', async () => {
456
451
  const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-runtime-locked-'))
457
452
  await createLegacyMiniconda(root)
458
453
  const kernel = createKernel(root)
@@ -467,10 +462,15 @@ test('Conda install reports manual recovery when the old runtime cannot be remov
467
462
  }
468
463
 
469
464
  try {
465
+ const packets = []
470
466
  await assert.rejects(
471
- conda._install({ dependencies: [] }, () => {}),
472
- /delete that folder manually/
467
+ conda._install({ dependencies: [] }, (data, type) => packets.push({ data, type })),
468
+ process.platform === 'win32' ? /__PINOKIO_BLOCKER__/ : /delete that folder manually/
473
469
  )
470
+ if (process.platform === 'win32') {
471
+ const blocked = packets.find((packet) => packet.type === 'path.remove.blocked')
472
+ assert.equal(blocked && blocked.data && blocked.data.code, 'PINOKIO_PATH_REMOVE_BLOCKED')
473
+ }
474
474
  } finally {
475
475
  fsModule.promises.rm = originalRm
476
476
  }
@@ -0,0 +1,21 @@
1
+ if (process.platform !== "win32") {
2
+ process.exit(2)
3
+ }
4
+
5
+ const koffi = require("koffi")
6
+ const kernel32 = koffi.load("kernel32.dll")
7
+ const loadLibrary = kernel32.func("void * __stdcall LoadLibraryW(str16 path)")
8
+ const freeLibrary = kernel32.func("int32_t __stdcall FreeLibrary(void *module)")
9
+
10
+ const moduleHandle = loadLibrary(process.argv[2])
11
+ if (!moduleHandle) {
12
+ process.stderr.write("LoadLibraryW failed\n")
13
+ process.exit(1)
14
+ }
15
+
16
+ process.stdout.write("READY\n")
17
+ process.stdin.resume()
18
+ process.stdin.once("data", () => {
19
+ freeLibrary(moduleHandle)
20
+ process.exit(0)
21
+ })