Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a7b222a
chore: add .github/workflows/fleet-analyze.yml
LeanBitLab Apr 30, 2026
94e4500
chore: add .github/workflows/fleet-dispatch.yml
LeanBitLab Apr 30, 2026
0d1d64a
chore: add .github/workflows/fleet-merge.yml
LeanBitLab Apr 30, 2026
9932e03
chore: add .github/workflows/jules-merge-conflicts.yml
LeanBitLab Apr 30, 2026
bf034f9
chore: add .github/workflows/fleet-label.yml
LeanBitLab Apr 30, 2026
34b13f6
chore: add example fleet goal
LeanBitLab Apr 30, 2026
ee9b028
Merge pull request #30 from LeanBitLab/fleet-init-1777570352841
LeanBitLab Apr 30, 2026
52155ac
fleet: dispatch task to fix column top-alignment bug
Apr 30, 2026
f6c9e29
Fixes #31: Fix vertical alignment bug in columns
LeanBitLab Apr 30, 2026
329ddf3
chore: remove jules-merge-conflicts workflow to fix CI failure
LeanBitLab Apr 30, 2026
b2ad584
Add conflict detection workflow for PRs
LeanBitLab Apr 30, 2026
b467a2f
Merge pull request #32 from LeanBitLab/fix/issue-31-vertical-alignmen…
LeanBitLab Apr 30, 2026
7fa340d
Fix missing dependencies in jules-merge GitHub Action
LeanBitLab Apr 30, 2026
15a2140
Provide GitHub token to jules-merge action
LeanBitLab Apr 30, 2026
4b42ad0
Delete .fleet/goals/fix-column-alignment.md
LeanBitLab May 1, 2026
52c34df
Merge pull request #33 from LeanBitLab/fix-jules-merge-deps-175596843…
LeanBitLab May 1, 2026
36d4922
workflow: remove cron schedule from fleet dispatch
May 1, 2026
e258bab
fix: right column alignment for large font sizes
May 1, 2026
1c0fa03
feat: presets system, better defaults, setup permissions, keep-alive …
May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .fleet/goals/example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
milestone: "1"
---

# Example Fleet Goal

Analyze the codebase for potential improvements and create
issues for the engineering team.

## Tools
- Test Coverage: `npx vitest --coverage --json`

## Assessment Hints
- Focus on missing error handling in API routes
- Look for hardcoded configuration values

## Insight Hints
- Report on overall test coverage metrics
- Note any unusually complex functions (cyclomatic complexity)

## Constraints
- Do NOT propose changes already covered by open issues
- Do NOT propose changes rejected in recently closed issues
- Keep tasks small and isolated — one logical change per issue
42 changes: 42 additions & 0 deletions .github/workflows/fleet-analyze.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Generated by @google/jules-fleet init
# https://github.com/google-labs-code/jules-sdk

name: Fleet Analyze

on:
schedule:
- cron: '0 */6 * * *'
workflow_dispatch:
inputs:
goal:
description: 'Path to goal file (or blank for all)'
type: string
default: ''
milestone:
description: 'Milestone ID override'
type: string
default: ''

concurrency:
group: fleet-analyze
cancel-in-progress: false

jobs:
analyze:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
pull-requests: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npx -y --package=@google/jules-fleet jules-fleet analyze --goal "${{ inputs.goal }}" --milestone "${{ inputs.milestone }}"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}
57 changes: 57 additions & 0 deletions .github/workflows/fleet-dispatch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Generated by @google/jules-fleet init
# https://github.com/google-labs-code/jules-sdk

name: Fleet Dispatch

on:
workflow_dispatch:
inputs:
milestone:
description: 'Milestone ID to dispatch (leave empty to dispatch all)'
type: string
required: false

concurrency:
group: fleet-dispatch
cancel-in-progress: false

jobs:
discover:
runs-on: ubuntu-latest
outputs:
milestones: ${{ steps.list.outputs.milestones }}
steps:
- name: Resolve milestones
id: list
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INPUT_MILESTONE: ${{ inputs.milestone }}
run: |
if [ -n "$INPUT_MILESTONE" ]; then
echo "milestones=[\"$INPUT_MILESTONE\"]" >> "$GITHUB_OUTPUT"
else
milestones=$(gh api repos/${{ github.repository }}/milestones --jq '[.[].number | tostring]')
echo "milestones=$milestones" >> "$GITHUB_OUTPUT"
fi

dispatch:
needs: discover
runs-on: ubuntu-latest
strategy:
matrix:
milestone: ${{ fromJSON(needs.discover.outputs.milestones) }}
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npx -y --package=@google/jules-fleet jules-fleet dispatch --milestone ${{ matrix.milestone }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}
45 changes: 45 additions & 0 deletions .github/workflows/fleet-label.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Fleet Label PR
on:
pull_request:
types: [opened, edited, synchronize]

permissions:
pull-requests: write
issues: read

jobs:
label_pr:
runs-on: ubuntu-latest
steps:
- name: Check linked issue and apply label/milestone
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
REPO: ${{ github.repository }}
run: |
# Use GitHub's own closing keyword resolution to find linked issues
ISSUE_NUMBER=$(gh pr view "$PR_URL" --json closingIssuesReferences --jq '.closingIssuesReferences[0].number // empty')

if [ -z "$ISSUE_NUMBER" ]; then
echo "No closing issue reference found on this PR. Exiting."
exit 0
fi

echo "Found linked issue: #$ISSUE_NUMBER"

# Check if the linked issue has the 'fleet' label
HAS_FLEET=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json labels --jq '[.labels[].name] | any(. == "fleet")')

if [ "$HAS_FLEET" = "true" ]; then
echo "Linked issue has 'fleet' label. Applying 'fleet-merge-ready' to PR."
gh pr edit "$PR_URL" --add-label "fleet-merge-ready"

# Check if linked issue has a milestone and copy it
MILESTONE_TITLE=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json milestone --jq '.milestone.title // empty')
if [ -n "$MILESTONE_TITLE" ]; then
echo "Applying milestone '$MILESTONE_TITLE' to PR."
gh pr edit "$PR_URL" --milestone "$MILESTONE_TITLE"
fi
else
echo "Linked issue does not have 'fleet' label. Ignoring."
fi
54 changes: 54 additions & 0 deletions .github/workflows/fleet-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Generated by @google/jules-fleet init
# https://github.com/google-labs-code/jules-sdk

name: Fleet Merge

on:
schedule:
- cron: '0 */3 * * *'
workflow_dispatch:
inputs:
mode:
description: 'PR selection mode'
type: choice
options:
- label
- fleet-run
default: 'label'
fleet_run_id:
description: 'Fleet run ID (required for fleet-run mode)'
type: string
default: ''
redispatch:
description: 'Enable smart conflict resolution'
type: boolean
default: true

concurrency:
group: fleet-merge
cancel-in-progress: true

jobs:
merge:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: |
REDISPATCH_FLAG="--redispatch"
if [ "${{ inputs.redispatch }}" = "false" ]; then
REDISPATCH_FLAG=""
fi
npx -y --package=@google/jules-fleet jules-fleet merge --mode ${{ inputs.mode || 'label' }} --run-id "${{ inputs.fleet_run_id }}" $REDISPATCH_FLAG
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}
25 changes: 25 additions & 0 deletions .github/workflows/jules-merge-conflicts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by @google/jules-fleet init
# This workflow scans PRs for overlapping file changes.
name: Conflict Detection

on:
pull_request:
branches: [main]

permissions:
contents: read
pull-requests: read

jobs:
scan-overlaps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Scan for overlapping changes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
npx -y --package=@google/jules-sdk --package=@modelcontextprotocol/sdk --package=@google/jules-merge jules-merge scan --json '{"prs":[${{ github.event.pull_request.number }}],"repo":"${{ github.repository }}","base":"${{ github.event.pull_request.base.ref }}"}'
27 changes: 17 additions & 10 deletions app/src/main/java/com/leanbitlab/lwidget/AwidgetProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -197,24 +197,24 @@ class AwidgetProvider : AppWidgetProvider() {

// --- Load Preferences ---
val showTime = prefs.getBoolean("show_time", true)
val sizeTime = prefs.getFloat("size_time", 64f)
val sizeTime = prefs.getFloat("size_time", 56f)

val showDate = prefs.getBoolean("show_date", true)
val sizeDate = prefs.getFloat("size_date", 14f)
val sizeDate = prefs.getFloat("size_date", 16f)

val showBattery = prefs.getBoolean("show_battery", true)
val sizeBattery = prefs.getFloat("size_battery", 24f)
val boldBattery = prefs.getBoolean("bold_battery", false)
val sizeBattery = prefs.getFloat("size_battery", 32f)
val boldBattery = prefs.getBoolean("bold_battery", true)

val showTemp = prefs.getBoolean("show_temp", true)
val showTemp = prefs.getBoolean("show_temp", false)
val sizeTemp = prefs.getFloat("size_temp", 18f)
val boldTemp = prefs.getBoolean("bold_temp", false)

val showWeatherCondition = prefs.getBoolean("show_weather_condition", false)
val sizeWeather = prefs.getFloat("size_weather", 18f)
val boldWeather = prefs.getBoolean("bold_weather", false)

var showEvents = prefs.getBoolean("show_events", true)
var showEvents = prefs.getBoolean("show_events", false)
if (showEvents && androidx.core.content.ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALENDAR) != android.content.pm.PackageManager.PERMISSION_GRANTED) {
showEvents = false
}
Expand Down Expand Up @@ -250,7 +250,7 @@ class AwidgetProvider : AppWidgetProvider() {
val sizeWorldClock = prefs.getFloat("size_world_clock", 18f)
val worldClockZoneStr = prefs.getString("world_clock_zone_str", "UTC") ?: "UTC"

val showStorage = prefs.getBoolean("show_storage", true)
val showStorage = prefs.getBoolean("show_storage", false)
val sizeStorage = prefs.getFloat("size_storage", 14f)

var showTasks = prefs.getBoolean("show_tasks", false)
Expand Down Expand Up @@ -286,7 +286,7 @@ class AwidgetProvider : AppWidgetProvider() {

val fontStyle = prefs.getInt("font_style", 0)

val bgOpacity = prefs.getFloat("bg_opacity", 100f)
val bgOpacity = prefs.getFloat("bg_opacity", 85f)
val textColorPrimaryIdx = prefs.getInt("text_color_primary_idx", 0)
val textColorSecondaryIdx = prefs.getInt("text_color_secondary_idx", 0)
val bgColorIdx = prefs.getInt("bg_color_idx", 0)
Expand Down Expand Up @@ -366,7 +366,7 @@ class AwidgetProvider : AppWidgetProvider() {
}
}

val showOutline = prefs.getBoolean("show_outline", true)
val showOutline = prefs.getBoolean("show_outline", false)
val outlineColor = resolveOutlineColor(outlineColorIdx)
views.setImageViewResource(R.id.widget_outline, R.drawable.widget_bg_outline)
views.setViewVisibility(R.id.widget_outline, if (showOutline) android.view.View.VISIBLE else android.view.View.GONE)
Expand Down Expand Up @@ -753,12 +753,19 @@ class AwidgetProvider : AppWidgetProvider() {
// Calculate cumulative Y positions for each visible item
val rightDp = context.resources.displayMetrics.density
var cumulativeTopDp = 24f // Starting top margin from top of widget
var isFirstVisible = true
for (entry in rightStack) {
if (entry.isVisible) {
if (isFirstVisible) {
// Compensate for font intrinsic top padding (matches left side logic)
val intrinsicGap = entry.size * 0.18f
cumulativeTopDp = maxOf(0f, 24f - intrinsicGap)
isFirstVisible = false
}
val topPaddingPx = (cumulativeTopDp * rightDp).toInt()
views.setViewPadding(entry.viewId, 0, topPaddingPx, 0, 0)
// Advance by this item's height + small gap
val itemHeightDp = entry.size * 1.2f // approximate line height
val itemHeightDp = entry.size * 1.15f // approximate line height
cumulativeTopDp += itemHeightDp + 2f
}
}
Expand Down
Loading
Loading