pinokiod 7.5.9 → 7.5.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.
@@ -180,10 +180,7 @@ class Shell {
180
180
  req.params.rows = req.client.rows
181
181
  req.params.cols = req.client.cols
182
182
  }
183
- Object.defineProperty(req.params, CondaRuntimeGuard.SHELL_RUN_GUARD, {
184
- configurable: true,
185
- value: true,
186
- })
183
+ options[CondaRuntimeGuard.SHELL_RUN_GUARD_OPTION] = true
187
184
  let response = await kernel.shell.run(req.params, options, async (stream, type) => {
188
185
  // process.stdout.write(stream.raw)
189
186
  ondata(stream, type)
package/kernel/index.js CHANGED
@@ -59,7 +59,7 @@ const VARS = {
59
59
 
60
60
  //const memwatch = require('@airbnb/node-memwatch');
61
61
  class Kernel {
62
- schema = "<=7.4.0"
62
+ schema = "<=8.0.0"
63
63
  constructor(store) {
64
64
  this.fetch = fetch
65
65
 
package/kernel/shell.js CHANGED
@@ -390,8 +390,9 @@ class Shell {
390
390
  }
391
391
  return chunks.join(" ")
392
392
  }
393
- async start(params, ondata) {
393
+ async start(params, ondata, options = {}) {
394
394
  this.ondata = ondata
395
+ this.condaRuntimeGuard = !!(options && options[CondaRuntimeGuard.SHELL_RUN_GUARD_OPTION])
395
396
  if (this.nudgeRestoreTimer) {
396
397
  clearTimeout(this.nudgeRestoreTimer)
397
398
  this.nudgeRestoreTimer = null
@@ -1354,7 +1355,7 @@ class Shell {
1354
1355
  ? this.kernel.bin.path("miniforge")
1355
1356
  : this.kernel.path("bin/miniforge")
1356
1357
  const flowSessionKey = [this.id, this.start_time].filter(Boolean).join(':')
1357
- if (params[CondaRuntimeGuard.SHELL_RUN_GUARD]) {
1358
+ if (this.condaRuntimeGuard) {
1358
1359
  CondaRuntimeGuard.applyCondaRuntimeGuard(params, {
1359
1360
  cwd: params.path,
1360
1361
  managedBasePrefix,
@@ -1,7 +1,7 @@
1
1
  const path = require('path')
2
2
  const unparse = require('yargs-unparser-custom-flag')
3
3
 
4
- const SHELL_RUN_GUARD = Symbol('pinokio.shellRunCondaRuntimeGuard')
4
+ const SHELL_RUN_GUARD_OPTION = 'condaRuntimeGuard'
5
5
  const noticeSessions = new Set()
6
6
 
7
7
  const MUTATING_COMMANDS = new Set([
@@ -24,6 +24,7 @@ const PROTECTED_PACKAGES = new Set([
24
24
  'python',
25
25
  'conda-libmamba-solver',
26
26
  ])
27
+ const PROTECTED_PACKAGE_NAMES = Array.from(PROTECTED_PACKAGES).sort((a, b) => b.length - a.length)
27
28
 
28
29
  const VALUE_FLAGS = new Set([
29
30
  '-c',
@@ -34,9 +35,15 @@ const VALUE_FLAGS = new Set([
34
35
  '--name',
35
36
  '-p',
36
37
  '--prefix',
38
+ '--revision',
37
39
  '--solver',
38
40
  ])
39
41
 
42
+ const FILE_FLAGS = new Set([
43
+ '-f',
44
+ '--file',
45
+ ])
46
+
40
47
  function pathApi(platform) {
41
48
  return platform === 'win32' ? path.win32 : path.posix
42
49
  }
@@ -217,12 +224,19 @@ function splitShellSegments(input, context = {}) {
217
224
  return parts
218
225
  }
219
226
 
220
- function getExecutableToken(tokens) {
221
- let index = 0
227
+ function getExecutableToken(tokens, startIndex = 0, context = {}) {
228
+ let index = startIndex
222
229
  while (index < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[index])) {
223
230
  index++
224
231
  }
225
- if (tokens[index] === '&' || String(tokens[index]).toLowerCase() === 'call') {
232
+ const token = String(tokens[index] || '')
233
+ const lower = token.toLowerCase()
234
+ const shellName = String(context.shellName || '').toLowerCase()
235
+ const platform = context.platform || process.platform
236
+ if (
237
+ (token === '&' && (shellName.includes('powershell') || shellName.includes('pwsh')))
238
+ || (lower === 'call' && (platform === 'win32' || shellName.includes('cmd')))
239
+ ) {
226
240
  index++
227
241
  }
228
242
  return { executable: tokens[index] || '', index }
@@ -245,22 +259,60 @@ function isCondaExecutable(executable, context) {
245
259
  return base === 'conda' || base === 'conda.exe' || base === 'conda.bat' || base === 'conda.cmd'
246
260
  }
247
261
 
262
+ function isPythonExecutable(executable, context) {
263
+ const platform = context.platform || process.platform
264
+ const base = executableBasename(executable, platform)
265
+ return /^python(?:\d+(?:\.\d+)?)?(?:\.exe)?$/.test(base)
266
+ }
267
+
268
+ function isCondaModuleToken(token) {
269
+ return String(token || '').toLowerCase() === 'conda'
270
+ }
271
+
272
+ function findCondaInvocation(tokens, context, startIndex = 0) {
273
+ const { executable, index: executableIndex } = getExecutableToken(tokens, startIndex, context)
274
+ if (isCondaExecutable(executable, context)) {
275
+ return { executableIndex, argsStart: executableIndex + 1 }
276
+ }
277
+ if (isPythonExecutable(executable, context)) {
278
+ if (tokens[executableIndex + 1] === '-m' && isCondaModuleToken(tokens[executableIndex + 2])) {
279
+ return { executableIndex, argsStart: executableIndex + 3 }
280
+ }
281
+ }
282
+ return null
283
+ }
284
+
248
285
  function resolveWrapperTarget(params, context) {
249
286
  const conda = params ? params.conda : undefined
250
287
  const platform = context.platform || process.platform
251
288
  const cwd = context.cwd || (params && params.path) || process.cwd()
289
+ const managedBasePrefix = context.managedBasePrefix || ''
252
290
  if (!conda) {
253
- return { kind: 'managed-base', source: 'wrapper', prefix: context.managedBasePrefix || '' }
291
+ return { kind: 'managed-base', source: 'wrapper', prefix: managedBasePrefix }
292
+ }
293
+ if (conda && conda.skip === true) {
294
+ return { kind: 'unknown', source: 'wrapper-skip' }
254
295
  }
255
296
  if (typeof conda === 'string') {
256
- return { kind: 'app-env', source: 'wrapper', prefix: resolvePathFrom(cwd, conda, platform) }
297
+ const prefix = resolvePathFrom(cwd, conda, platform)
298
+ if (managedBasePrefix && isSamePath(prefix, managedBasePrefix, platform)) {
299
+ return { kind: 'managed-base', source: 'wrapper', prefix: managedBasePrefix }
300
+ }
301
+ return { kind: 'app-env', source: 'wrapper', prefix }
302
+ }
303
+ if (conda && conda.activate === 'minimal' && (conda.path || conda.name)) {
304
+ return { kind: 'managed-base', source: 'wrapper', prefix: managedBasePrefix }
257
305
  }
258
306
  if (conda && conda.path) {
259
- return { kind: 'app-env', source: 'wrapper', prefix: resolvePathFrom(cwd, conda.path, platform) }
307
+ const prefix = resolvePathFrom(cwd, conda.path, platform)
308
+ if (managedBasePrefix && isSamePath(prefix, managedBasePrefix, platform)) {
309
+ return { kind: 'managed-base', source: 'wrapper', prefix: managedBasePrefix }
310
+ }
311
+ return { kind: 'app-env', source: 'wrapper', prefix }
260
312
  }
261
313
  if (conda && conda.name) {
262
314
  if (conda.name === 'base') {
263
- return { kind: 'managed-base', source: 'wrapper', prefix: context.managedBasePrefix || '' }
315
+ return { kind: 'managed-base', source: 'wrapper', prefix: managedBasePrefix }
264
316
  }
265
317
  return {
266
318
  kind: 'app-env',
@@ -271,8 +323,8 @@ function resolveWrapperTarget(params, context) {
271
323
  return { kind: 'unknown', source: 'wrapper' }
272
324
  }
273
325
 
274
- function parseCommandTarget(tokens, executableIndex) {
275
- for (let i = executableIndex + 1; i < tokens.length; i++) {
326
+ function parseCommandTarget(tokens, argsStart) {
327
+ for (let i = argsStart; i < tokens.length; i++) {
276
328
  const token = tokens[i]
277
329
  if (token === '-p' || token === '--prefix') {
278
330
  return { type: 'prefix', value: tokens[i + 1] || '' }
@@ -309,13 +361,13 @@ function refineTargetFromCommandArgs(target, commandTarget, params, context) {
309
361
  return { kind: 'app-env', source: 'command-target', prefix: resolved }
310
362
  }
311
363
 
312
- function resolveTarget(tokens, executableIndex, params, context) {
313
- const wrapperTarget = resolveWrapperTarget(params, context)
314
- return refineTargetFromCommandArgs(wrapperTarget, parseCommandTarget(tokens, executableIndex), params, context)
364
+ function resolveTarget(tokens, argsStart, params, context, wrapperTargetOverride) {
365
+ const wrapperTarget = wrapperTargetOverride || resolveWrapperTarget(params, context)
366
+ return refineTargetFromCommandArgs(wrapperTarget, parseCommandTarget(tokens, argsStart), params, context)
315
367
  }
316
368
 
317
- function findSubcommand(tokens, executableIndex) {
318
- for (let i = executableIndex + 1; i < tokens.length; i++) {
369
+ function findSubcommand(tokens, argsStart) {
370
+ for (let i = argsStart; i < tokens.length; i++) {
319
371
  const token = String(tokens[i] || '').toLowerCase()
320
372
  if (!token || token.startsWith('-')) {
321
373
  if (VALUE_FLAGS.has(token)) {
@@ -338,13 +390,8 @@ function findSubcommand(tokens, executableIndex) {
338
390
  return null
339
391
  }
340
392
 
341
- function isEnvironmentTargetingSubcommand(subcommand) {
342
- return subcommand && (
343
- subcommand.name === 'create'
344
- || subcommand.name === 'env create'
345
- || subcommand.name === 'env remove'
346
- || subcommand.name === 'env update'
347
- )
393
+ function isCreateSubcommand(subcommand) {
394
+ return subcommand && (subcommand.name === 'create' || subcommand.name === 'env create')
348
395
  }
349
396
 
350
397
  function normalizePackageSpec(token) {
@@ -355,12 +402,65 @@ function normalizePackageSpec(token) {
355
402
  return scoped.split(/[=<>!~]/)[0].trim().toLowerCase()
356
403
  }
357
404
 
405
+ function protectedPackageFromArchive(token, context) {
406
+ if (!token || token.startsWith('-')) {
407
+ return ''
408
+ }
409
+ const platform = context.platform || process.platform
410
+ const base = executableBasename(token, platform)
411
+ const lower = base.toLowerCase()
412
+ const ext = lower.endsWith('.tar.bz2')
413
+ ? '.tar.bz2'
414
+ : lower.endsWith('.conda')
415
+ ? '.conda'
416
+ : ''
417
+ if (!ext) {
418
+ return ''
419
+ }
420
+ for (const pkg of PROTECTED_PACKAGE_NAMES) {
421
+ const prefix = `${pkg}-`
422
+ if (!lower.startsWith(prefix)) {
423
+ continue
424
+ }
425
+ const body = lower.slice(prefix.length, -ext.length)
426
+ const buildSeparator = body.indexOf('-')
427
+ if (/^\d/.test(body) && buildSeparator > 0 && buildSeparator < body.length - 1) {
428
+ return pkg
429
+ }
430
+ }
431
+ return ''
432
+ }
433
+
434
+ function hasFlag(tokens, startIndex, flags) {
435
+ return tokens.slice(startIndex).some((token) => {
436
+ if (flags.has(token)) {
437
+ return true
438
+ }
439
+ if (String(token).startsWith('--') && String(token).includes('=')) {
440
+ return flags.has(String(token).slice(0, String(token).indexOf('=')))
441
+ }
442
+ return false
443
+ })
444
+ }
445
+
358
446
  function hasAllFlag(tokens, startIndex) {
359
- return tokens.slice(startIndex).some((token) => token === '--all')
447
+ return hasFlag(tokens, startIndex, new Set(['--all']))
360
448
  }
361
449
 
362
450
  function hasDryRunFlag(tokens, startIndex) {
363
- return tokens.slice(startIndex).some((token) => token === '--dry-run')
451
+ return hasFlag(tokens, startIndex, new Set(['--dry-run', '-d']))
452
+ }
453
+
454
+ function hasUpdateAllFlag(tokens, startIndex) {
455
+ return hasFlag(tokens, startIndex, new Set(['--update-all', '--all']))
456
+ }
457
+
458
+ function hasRevisionFlag(tokens, startIndex) {
459
+ return hasFlag(tokens, startIndex, new Set(['--revision']))
460
+ }
461
+
462
+ function hasFileFlag(tokens, startIndex) {
463
+ return hasFlag(tokens, startIndex, FILE_FLAGS)
364
464
  }
365
465
 
366
466
  function explicitPackageNames(tokens, startIndex) {
@@ -388,40 +488,145 @@ function explicitPackageNames(tokens, startIndex) {
388
488
  return packages
389
489
  }
390
490
 
391
- function protectedPackageFromSubcommand(tokens, subcommand) {
491
+ function protectedPackageFromSubcommand(tokens, subcommand, context) {
392
492
  const packages = explicitPackageNames(tokens, subcommand.endIndex + 1)
393
- return packages.find((pkg) => PROTECTED_PACKAGES.has(pkg)) || ''
493
+ const explicitPackage = packages.find((pkg) => PROTECTED_PACKAGES.has(pkg))
494
+ if (explicitPackage) {
495
+ return explicitPackage
496
+ }
497
+ if (subcommand.name !== 'install') {
498
+ return ''
499
+ }
500
+ for (let i = subcommand.endIndex + 1; i < tokens.length; i++) {
501
+ const token = tokens[i]
502
+ if (!token) {
503
+ continue
504
+ }
505
+ if (token.startsWith('--') && token.includes('=')) {
506
+ continue
507
+ }
508
+ if (VALUE_FLAGS.has(token)) {
509
+ i++
510
+ continue
511
+ }
512
+ if (token.startsWith('-')) {
513
+ continue
514
+ }
515
+ const archivePackage = protectedPackageFromArchive(token, context)
516
+ if (archivePackage) {
517
+ return archivePackage
518
+ }
519
+ }
520
+ return ''
394
521
  }
395
522
 
396
523
  function isListedBroadMutation(tokens, subcommand, target) {
397
- if ((subcommand.name === 'update' || subcommand.name === 'upgrade') && hasAllFlag(tokens, subcommand.endIndex + 1)) {
524
+ const startIndex = subcommand.endIndex + 1
525
+ if ((subcommand.name === 'update' || subcommand.name === 'upgrade') && hasUpdateAllFlag(tokens, subcommand.endIndex + 1)) {
526
+ return true
527
+ }
528
+ if (subcommand.name === 'install' && (hasUpdateAllFlag(tokens, startIndex) || hasRevisionFlag(tokens, startIndex))) {
529
+ return true
530
+ }
531
+ if ((subcommand.name === 'remove' || subcommand.name === 'uninstall') && hasAllFlag(tokens, startIndex)) {
532
+ return true
533
+ }
534
+ if ((subcommand.name === 'create' || subcommand.name === 'env create') && target.source === 'command-target') {
535
+ return true
536
+ }
537
+ if (subcommand.name === 'env remove' && target.source === 'command-target') {
538
+ return true
539
+ }
540
+ if (subcommand.name === 'env update') {
541
+ return true
542
+ }
543
+ if (['install', 'update', 'upgrade'].includes(subcommand.name) && hasFileFlag(tokens, startIndex)) {
398
544
  return true
399
545
  }
400
- return subcommand.name === 'env remove' && target.source === 'command-target'
546
+ return false
401
547
  }
402
548
 
403
- function classifyCommandTokens(tokens, params = {}, context = {}) {
404
- const { executable, index: executableIndex } = getExecutableToken(tokens)
405
- if (!isCondaExecutable(executable, context)) {
549
+ function parseCondaRun(tokens, argsStart, params, context, wrapperTarget) {
550
+ let commandTarget = null
551
+ let commandStart = argsStart + 1
552
+ for (let i = argsStart + 1; i < tokens.length; i++) {
553
+ const token = tokens[i]
554
+ if (token === '-p' || token === '--prefix') {
555
+ commandTarget = { type: 'prefix', value: tokens[i + 1] || '' }
556
+ i++
557
+ commandStart = i + 1
558
+ continue
559
+ }
560
+ if (String(token).startsWith('--prefix=')) {
561
+ commandTarget = { type: 'prefix', value: token.slice('--prefix='.length) }
562
+ commandStart = i + 1
563
+ continue
564
+ }
565
+ if (token === '-n' || token === '--name') {
566
+ commandTarget = { type: 'name', value: tokens[i + 1] || '' }
567
+ i++
568
+ commandStart = i + 1
569
+ continue
570
+ }
571
+ if (String(token).startsWith('--name=')) {
572
+ commandTarget = { type: 'name', value: token.slice('--name='.length) }
573
+ commandStart = i + 1
574
+ continue
575
+ }
576
+ if (token === '--cwd') {
577
+ i++
578
+ commandStart = i + 1
579
+ continue
580
+ }
581
+ if (String(token).startsWith('--cwd=')) {
582
+ commandStart = i + 1
583
+ continue
584
+ }
585
+ if (token === '--') {
586
+ commandStart = i + 1
587
+ break
588
+ }
589
+ if (String(token).startsWith('-')) {
590
+ commandStart = i + 1
591
+ continue
592
+ }
593
+ commandStart = i
594
+ break
595
+ }
596
+ const target = refineTargetFromCommandArgs(wrapperTarget, commandTarget, params, context)
597
+ return { commandStart, target }
598
+ }
599
+
600
+ function classifyCommandTokens(tokens, params = {}, context = {}, startIndex = 0, wrapperTargetOverride = null) {
601
+ const invocation = findCondaInvocation(tokens, context, startIndex)
602
+ if (!invocation) {
406
603
  return { shouldSkip: false }
407
604
  }
408
- const target = resolveTarget(tokens, executableIndex, params, context)
605
+ const wrapperTarget = wrapperTargetOverride || resolveWrapperTarget(params, context)
606
+ const subcommand = findSubcommand(tokens, invocation.argsStart)
607
+ if (subcommand && subcommand.name === 'run') {
608
+ const run = parseCondaRun(tokens, invocation.argsStart, params, context, wrapperTarget)
609
+ return classifyCommandTokens(tokens, params, context, run.commandStart, run.target)
610
+ }
611
+ const target = resolveTarget(tokens, invocation.argsStart, params, context, wrapperTarget)
409
612
  if (target.kind !== 'managed-base') {
410
613
  return { shouldSkip: false }
411
614
  }
412
- const subcommand = findSubcommand(tokens, executableIndex)
413
615
  if (!subcommand || !subcommand.mutating) {
414
616
  return { shouldSkip: false }
415
617
  }
416
- if (hasDryRunFlag(tokens, subcommand.endIndex + 1)) {
618
+ if (hasDryRunFlag(tokens, invocation.argsStart)) {
417
619
  return { shouldSkip: false }
418
620
  }
419
621
 
420
- if (isEnvironmentTargetingSubcommand(subcommand) && target.source !== 'command-target') {
622
+ if (isCreateSubcommand(subcommand) && target.source !== 'command-target') {
623
+ return { shouldSkip: false }
624
+ }
625
+ if (subcommand.name === 'env remove' && target.source !== 'command-target') {
421
626
  return { shouldSkip: false }
422
627
  }
423
628
 
424
- const protectedPackage = protectedPackageFromSubcommand(tokens, subcommand)
629
+ const protectedPackage = protectedPackageFromSubcommand(tokens, subcommand, context)
425
630
  if (!protectedPackage && !isListedBroadMutation(tokens, subcommand, target)) {
426
631
  return { shouldSkip: false }
427
632
  }
@@ -435,72 +640,36 @@ function classifyCommandTokens(tokens, params = {}, context = {}) {
435
640
  }
436
641
  }
437
642
 
438
- function noopCommand() {
439
- return 'echo Pinokio skipped a Conda setup command. Pinokio is continuing.'
440
- }
441
-
442
643
  function classifySegment(segment, params, context) {
443
644
  const parsed = shellTokenize(segment, context)
444
645
  if (!parsed.closed) {
445
646
  return { shouldSkip: false }
446
647
  }
447
- return {
448
- ...classifyCommandTokens(parsed.tokens, params, context),
449
- tokens: parsed.tokens,
450
- }
648
+ return classifyCommandTokens(parsed.tokens, params, context)
451
649
  }
452
650
 
453
651
  function rewriteStringMessage(message, params, context) {
454
652
  const parts = splitShellSegments(message, context)
455
653
  const skipped = []
456
- const hasUnsafeSeparator = parts.some((part) => part.type === 'unsafe-separator')
457
654
 
458
- if (hasUnsafeSeparator) {
459
- for (const part of parts) {
460
- if (part.type !== 'segment') {
461
- continue
462
- }
463
- const body = part.text.trim()
464
- if (!body) {
465
- continue
466
- }
467
- const classification = classifySegment(body, params, context)
468
- if (classification.shouldSkip) {
469
- skipped.push({
470
- command: body,
471
- reason: classification.reason,
472
- target: classification.target,
473
- })
474
- }
475
- }
476
- if (skipped.length > 0) {
477
- return { message: noopCommand(), skipped }
478
- }
479
- return { message, skipped }
480
- }
481
-
482
- const rewritten = parts.map((part) => {
655
+ for (const part of parts) {
483
656
  if (part.type !== 'segment') {
484
- return part.text
657
+ continue
485
658
  }
486
- const leading = (part.text.match(/^\s*/) || [''])[0]
487
- const trailing = (part.text.match(/\s*$/) || [''])[0]
488
659
  const body = part.text.trim()
489
660
  if (!body) {
490
- return part.text
661
+ continue
491
662
  }
492
663
  const classification = classifySegment(body, params, context)
493
- if (!classification.shouldSkip) {
494
- return part.text
664
+ if (classification.shouldSkip) {
665
+ skipped.push({
666
+ command: body,
667
+ reason: classification.reason,
668
+ target: classification.target,
669
+ })
495
670
  }
496
- skipped.push({
497
- command: body,
498
- reason: classification.reason,
499
- target: classification.target,
500
- })
501
- return leading + noopCommand() + trailing
502
- }).join('')
503
- return { message: rewritten, skipped }
671
+ }
672
+ return { message: skipped.length > 0 ? '' : message, skipped }
504
673
  }
505
674
 
506
675
  function structuredTokens(message) {
@@ -525,7 +694,7 @@ function rewriteSingleMessage(message, params, context) {
525
694
  return { message, skipped: [] }
526
695
  }
527
696
  return {
528
- message: noopCommand(),
697
+ message: '',
529
698
  skipped: [{
530
699
  command: tokens.join(' '),
531
700
  reason: classification.reason,
@@ -565,29 +734,21 @@ function formatRawNotice(skip) {
565
734
  }
566
735
 
567
736
  function formatNotifyHtml(skipped) {
568
- const count = skipped.length
569
737
  const firstCommand = skipped[0] && skipped[0].command ? String(skipped[0].command) : ''
570
738
  const truncatedCommand = firstCommand.length > 240 ? `${firstCommand.slice(0, 237)}...` : firstCommand
571
- const title = count === 1
572
- ? 'Pinokio skipped a Conda setup command.'
573
- : `Pinokio skipped ${count} Conda setup commands.`
574
739
  const commandHtml = truncatedCommand
575
740
  ? [
576
- '<pre style="white-space:pre-wrap;margin:8px 0 0;font-size:12px;line-height:1.35;">',
741
+ '<code style="display:block;box-sizing:border-box;max-width:100%;white-space:pre-wrap;margin:0;padding:6px 8px;border:1px solid rgba(255,255,255,.16);border-radius:4px;background:rgba(255,255,255,.06);font-size:12px;line-height:1.35;">',
577
742
  escapeHtml(truncatedCommand),
578
- '</pre>',
743
+ '</code>',
579
744
  ].join('')
580
745
  : ''
581
- const moreHtml = count > 1
582
- ? `<br>${escapeHtml(`${count - 1} more skipped command${count === 2 ? ' is' : 's are'} listed in the terminal log.`)}`
583
- : ''
584
- return [
585
- `<b>${escapeHtml(title)}</b>`,
586
- escapeHtml('Pinokio already manages base Conda.'),
587
- escapeHtml('Pinokio is continuing.'),
746
+ const rows = [
747
+ `<b style="display:block;">${escapeHtml('Command skipped')}</b>`,
588
748
  commandHtml,
589
- `${escapeHtml('Details are in the terminal/log.')}${moreHtml}`,
590
- ].filter(Boolean).join('<br>')
749
+ `<span>${escapeHtml('No action needed. Pinokio already includes Conda.')}</span>`,
750
+ ].filter(Boolean).join('')
751
+ return `<div style="display:flex;flex-direction:column;gap:8px;">${rows}</div>`
591
752
  }
592
753
 
593
754
  function emitSkipNotices(params, skipped, context) {
@@ -610,10 +771,7 @@ function emitSkipNotices(params, skipped, context) {
610
771
  }
611
772
 
612
773
  function applyCondaRuntimeGuard(params, context = {}) {
613
- if (!params || !params[SHELL_RUN_GUARD]) {
614
- return { params, skipped: [] }
615
- }
616
- if (params.conda && params.conda.skip === true) {
774
+ if (!params) {
617
775
  return { params, skipped: [] }
618
776
  }
619
777
  const message = params.message
@@ -641,7 +799,7 @@ function resetNoticeSessionsForTest() {
641
799
  }
642
800
 
643
801
  module.exports = {
644
- SHELL_RUN_GUARD,
802
+ SHELL_RUN_GUARD_OPTION,
645
803
  applyCondaRuntimeGuard,
646
804
  resetNoticeSessionsForTest,
647
805
  }
package/kernel/shells.js CHANGED
@@ -632,7 +632,7 @@ class Shells {
632
632
  sh.mute = true
633
633
  sh.kill()
634
634
  }
635
- })
635
+ }, options)
636
636
  // If this shell ran under a workspace, rescan git repos for that workspace.
637
637
  // Snapshots are now always user-initiated via the backups UI; here we only
638
638
  // pin new repos to specific commits when this run was started from a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinokiod",
3
- "version": "7.5.9",
3
+ "version": "7.5.10",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -3698,9 +3698,9 @@ body.dark .swal2-styled.swal2-confirm{
3698
3698
  */
3699
3699
  .noty_bar {
3700
3700
  max-width: 300px !important;
3701
- background: rgba(0,0,0,0.9) !important;
3701
+ background: #1b1c1d !important;
3702
3702
  color: white !important;
3703
- border-bottom: none !important;
3703
+ border: 1px solid rgba(255, 255, 255, 0.08) !important;
3704
3704
  z-index: 1000000000000;
3705
3705
  }
3706
3706
  .noty_body a {