From 179c58ff73794bb2bb5a958c03d3581d9cfaf954 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Wed, 30 Sep 2026 12:42:56 -0700 Subject: [PATCH] macpal 0.2.9: --minimal still shows a live mission card A machine watching the Iris lanes runs its pal minimal (no git, tasks or pane) but still wants the lane board: the mission block now lays out in minimal mode when mission.json has one, and hides when collapsed or stale. --- macpal/Resources/Info.plist | 54 +++++++++++++-------------- macpal/Sources/FuserPlugin.swift | 63 +++++++++++++++++++------------- 2 files changed, 64 insertions(+), 53 deletions(-) diff --git a/macpal/Resources/Info.plist b/macpal/Resources/Info.plist index 52463f67dd..0e46cb2e4a 100644 --- a/macpal/Resources/Info.plist +++ b/macpal/Resources/Info.plist @@ -2,33 +2,33 @@ - CFBundleName - MacPal - CFBundleDisplayName - MacPal - CFBundleIdentifier - computer.aesthetic.macpal - CFBundleExecutable - MacPal - CFBundleIconFile - AppIcon - CFBundlePackageType - APPL - CFBundleShortVersionString - 0.2.8 - CFBundleVersion + CFBundleDisplayName + MacPal + CFBundleExecutable + MacPal + CFBundleIconFile + AppIcon + CFBundleIdentifier + computer.aesthetic.macpal + CFBundleName + MacPal + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.2.9 + CFBundleVersion 10 - LSMinimumSystemVersion - 13.0 - LSUIElement - - NSHumanReadableCopyright - © Aesthetic Computer - NSPrincipalClass - NSApplication - NSSupportsAutomaticTermination - - NSSupportsSuddenTermination - + LSMinimumSystemVersion + 13.0 + LSUIElement + + NSHumanReadableCopyright + © Aesthetic Computer + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + diff --git a/macpal/Sources/FuserPlugin.swift b/macpal/Sources/FuserPlugin.swift index 8f7edd9f74..952b92dbb9 100644 --- a/macpal/Sources/FuserPlugin.swift +++ b/macpal/Sources/FuserPlugin.swift @@ -419,7 +419,8 @@ final class FuserPlugin: NSObject, PalPlugin, WidthHinting { private var tick4 = 0 // git refresh every 4th tick (~4s) // minimal: hide every info row (status line, tasks, overtime, terminal pane) - // so the badge is just the avatar graphic + the name title. + // so the badge is just the avatar graphic + the name title, except a live + // mission, so a machine watching the lanes still shows the lane board. let minimal: Bool init(home: String, repo: String, minimal: Bool = false) { @@ -657,7 +658,11 @@ final class FuserPlugin: NSObject, PalPlugin, WidthHinting { // Reserved height from the y=12 baseline up to where the name sits — the // exact bottom-up stack the original badge computed. func stackHeight(in controller: PalController) -> CGFloat { - if minimal { return 0 } + // minimal keeps only a live mission: the lane board a machine is watching. + if minimal { + let h = missionMetrics(width: controller.fullWidth - 14).total + return h > 0 ? h + 8 : 0 + } // Mission mode stands the terminal pane down: its height leaves the // stack, so the todo list owns the badge's lower half until the // mission goes stale or is cleared. @@ -675,10 +680,10 @@ final class FuserPlugin: NSObject, PalPlugin, WidthHinting { func layoutRows(in controller: PalController, originY: CGFloat) { if minimal { statusField.isHidden = true; tasksField.isHidden = true - missionTitleField.isHidden = true; missionAgentField.isHidden = true - missionItemFields.forEach { $0.isHidden = true } overtimeField.isHidden = true; overtimeChip.isHidden = true paneContainer?.isHidden = true + let mm = missionMetrics(width: controller.fullWidth - 14) + layoutMission(y: originY, width: controller.fullWidth - 14, mm: mm) return } let base = originY // 12 in practice (single plugin) @@ -703,26 +708,7 @@ final class FuserPlugin: NSObject, PalPlugin, WidthHinting { statusField.isHidden = false statusField.frame = NSRect(x: 0, y: statusY, width: W, height: 22) - // Mission block: title, agent line, then items, top-down within its - // slot. Display-only — clicks pass through. - let missionVisible = mission != nil && missionH > 0 - missionTitleField.isHidden = !missionVisible - missionAgentField.isHidden = !(missionVisible && mm.agent > 0) - missionItemFields.forEach { $0.isHidden = !missionVisible } - if missionVisible { - var my = missionY + missionH - mm.title - missionTitleField.frame = NSRect(x: 7, y: my, width: missionW, height: mm.title) - if mm.agent > 0 { - my -= mm.agent + 1 - missionAgentField.frame = NSRect(x: 7, y: my, width: missionW, height: mm.agent) - } - my -= 5 - for (i, f) in missionItemFields.enumerated() { - my -= mm.items[i] - f.frame = NSRect(x: 7, y: my, width: missionW, height: mm.items[i]) - my -= 3 // breathing room between rows - } - } + layoutMission(y: missionY, width: missionW, mm: mm) overtimeField.isHidden = queueH <= 0 overtimeField.frame = NSRect(x: 6, y: overtimeY, width: W - 12, height: queueH) overtimeChip.isHidden = chipH <= 0 @@ -740,13 +726,38 @@ final class FuserPlugin: NSObject, PalPlugin, WidthHinting { } } + // Mission block: title, agent line, then items, top-down within its + // slot. Display-only — clicks pass through. + private func layoutMission(y missionY: CGFloat, width missionW: CGFloat, + mm: (title: CGFloat, agent: CGFloat, items: [CGFloat], total: CGFloat)) { + let missionVisible = mission != nil && mm.total > 0 + missionTitleField.isHidden = !missionVisible + missionAgentField.isHidden = !(missionVisible && mm.agent > 0) + missionItemFields.forEach { $0.isHidden = !missionVisible } + guard missionVisible else { return } + var my = missionY + mm.total - mm.title + missionTitleField.frame = NSRect(x: 7, y: my, width: missionW, height: mm.title) + if mm.agent > 0 { + my -= mm.agent + 1 + missionAgentField.frame = NSRect(x: 7, y: my, width: missionW, height: mm.agent) + } + my -= 5 + for (i, f) in missionItemFields.enumerated() { + my -= mm.items[i] + f.frame = NSRect(x: 7, y: my, width: missionW, height: mm.items[i]) + my -= 3 // breathing room between rows + } + } + func setCollapsed(_ collapsed: Bool) { if minimal { statusField.isHidden = true; tasksField.isHidden = true - missionTitleField.isHidden = true; missionAgentField.isHidden = true - missionItemFields.forEach { $0.isHidden = true } overtimeField.isHidden = true; overtimeChip.isHidden = true paneContainer?.isHidden = true + missionTitleField.isHidden = collapsed || mission == nil + missionAgentField.isHidden = collapsed || mission == nil + || missionAgentField.attributedStringValue.length == 0 + missionItemFields.forEach { $0.isHidden = collapsed || mission == nil } return } let hide = collapsed -- 2.51.2