omakit 0.4.0 → 0.4.2

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.
@@ -331,7 +331,12 @@ async function sampleConfig({ label, runIndex, config, plan, env, procRoot, sign
331
331
  onPhase(`run ${runIndex} of ${plan.runs}: ${label}, sampling for ${windowSeconds}s`)
332
332
  const started = utc()
333
333
  const t0 = Date.now()
334
- const cpu0 = cpuTicks(procRoot, pid) ?? 0
334
+ // A pid with no stat is a process that is gone, and a gone shell has no
335
+ // sample: nothing is read as zero in its place. Measured on 0.4.1: a pid
336
+ // absent from /proc "completed" the window with 0 ticks and a Pss of
337
+ // null read as 0 MB, a delta of minus the whole baseline.
338
+ const cpu0 = cpuTicks(procRoot, pid)
339
+ if (cpu0 === null) return { label, run: runIndex, failed: `the shell (pid ${pid}) is not in ${procRoot}` }
335
340
  const child0 = childTicks(procRoot, pid) ?? 0
336
341
  const rows = []
337
342
  const trace = []
@@ -355,7 +360,8 @@ async function sampleConfig({ label, runIndex, config, plan, env, procRoot, sign
355
360
  } catch {
356
361
  configRewritten = null
357
362
  }
358
- const cpu1 = cpuTicks(procRoot, pid) ?? cpu0
363
+ const cpu1 = cpuTicks(procRoot, pid)
364
+ if (cpu1 === null) return { label, run: runIndex, failed: `the shell (pid ${pid}) disappeared from ${procRoot} during the window` }
359
365
  const child1 = childTicks(procRoot, pid) ?? child0
360
366
  const memory = { pssKb: pssKb(procRoot, pid), rssKb: rssKb(procRoot, pid), memoryAt: "window-end", ...settled, trace }
361
367
  const seconds = (t1 - t0) / 1000
@@ -605,6 +611,13 @@ export async function measureWeigh(plan, { env = plan.env || process.env, procRo
605
611
  let restore = null
606
612
  let restoreProblem = null
607
613
  let comeBack = null
614
+ // What stopped the measurement early, an interrupt or a thrown error, is
615
+ // kept so the restore's outcome can be judged first: a restore that failed
616
+ // or did not verify is the fact the person is left with, and it is what
617
+ // is reported, with the stop as its context. Measured on 0.4.1: an
618
+ // interrupt propagated past a restore whose md5 differed, and the entry
619
+ // point closed with "shell.json was restored".
620
+ let stopped = null
608
621
  try {
609
622
  for (let runIndex = 1; runIndex <= plan.runs; runIndex += 1) {
610
623
  for (const { label, config } of configs) {
@@ -619,6 +632,8 @@ export async function measureWeigh(plan, { env = plan.env || process.env, procRo
619
632
  samples.push(sample)
620
633
  }
621
634
  }
635
+ } catch (error) {
636
+ stopped = error
622
637
  } finally {
623
638
  onPhase("restoring shell.json and restarting the shell")
624
639
  try {
@@ -642,7 +657,10 @@ export async function measureWeigh(plan, { env = plan.env || process.env, procRo
642
657
  onLine({ state: "fail", text: `the restore failed: ${error.message}; the backup is ${backup.backupFile}` })
643
658
  }
644
659
  }
645
- if (restoreProblem) throw new WeighError("restore-failed", `shell.json could not be restored from ${backup.backupFile}: ${restoreProblem.message}`, `Copy ${backup.backupFile} over ${plan.configFile} yourself, then run omarchy-restart-shell.`)
660
+ const because = stopped ? `. The measurement had stopped first: ${stopped.message}` : ""
661
+ if (restoreProblem) throw new WeighError("restore-failed", `shell.json could not be restored from ${backup.backupFile}: ${restoreProblem.message}${because}`, `Copy ${backup.backupFile} over ${plan.configFile} yourself, then run omarchy-restart-shell.`)
662
+ if (stopped && !restore.restored) throw new WeighError("restore-unverified", `shell.json differs from the backup after the restore; the backup ${backup.backupFile} is kept${because}`, `Compare ${backup.backupFile} with ${plan.configFile} and copy it over if the difference is not yours.`)
663
+ if (stopped) throw stopped
646
664
  const ended = utc()
647
665
  const config = {
648
666
  path: plan.configFile,
@@ -5,7 +5,7 @@
5
5
  // typed here is written anywhere.
6
6
 
7
7
  import { createInterface } from "node:readline"
8
- import { action, colourEnabled, COLUMNS, styler } from "../marketplace/style.mjs"
8
+ import { action, colourEnabled, outputColumns, styler } from "../marketplace/style.mjs"
9
9
 
10
10
  /**
11
11
  * The question as it is written to the terminal: the arrow line, wrapped
@@ -20,7 +20,7 @@ import { action, colourEnabled, COLUMNS, styler } from "../marketplace/style.mjs
20
20
  * @param {{ width?: number }} [options]
21
21
  * @returns {string} every line, joined, ending in `[y/N]: `
22
22
  */
23
- export function renderQuestion(question, c, { width = COLUMNS } = {}) {
23
+ export function renderQuestion(question, c, { width = outputColumns() } = {}) {
24
24
  return `${action(`${question} [y/N]:`, c, { indent: 0, width }).join("\n")} `
25
25
  }
26
26
 
@@ -28,7 +28,7 @@ export function renderQuestion(question, c, { width = COLUMNS } = {}) {
28
28
  * @param {{ input?: NodeJS.ReadStream, output?: NodeJS.WriteStream, colour?: boolean, question: string, width?: number }} options
29
29
  * @returns {Promise<boolean>} true only for `y` or `yes`, in any case; an empty line and the end of stdin are no
30
30
  */
31
- export function askYes({ input = process.stdin, output = process.stderr, colour = colourEnabled(output), question, width = COLUMNS }) {
31
+ export function askYes({ input = process.stdin, output = process.stderr, colour = colourEnabled(output), question, width = outputColumns(output) }) {
32
32
  const c = styler(colour)
33
33
  return new Promise((resolve) => {
34
34
  const rl = createInterface({ input, terminal: false })