Skip to content

Commit 30a9969

Browse files
authored
Merge pull request #36 from LeanBitLab/main
Add fleet workflows and fix vertical alignment issues
2 parents ad1be4d + 1c0fa03 commit 30a9969

13 files changed

Lines changed: 715 additions & 43 deletions

File tree

.fleet/goals/example.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
milestone: "1"
3+
---
4+
5+
# Example Fleet Goal
6+
7+
Analyze the codebase for potential improvements and create
8+
issues for the engineering team.
9+
10+
## Tools
11+
- Test Coverage: `npx vitest --coverage --json`
12+
13+
## Assessment Hints
14+
- Focus on missing error handling in API routes
15+
- Look for hardcoded configuration values
16+
17+
## Insight Hints
18+
- Report on overall test coverage metrics
19+
- Note any unusually complex functions (cyclomatic complexity)
20+
21+
## Constraints
22+
- Do NOT propose changes already covered by open issues
23+
- Do NOT propose changes rejected in recently closed issues
24+
- Keep tasks small and isolated — one logical change per issue
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Generated by @google/jules-fleet init
2+
# https://github.com/google-labs-code/jules-sdk
3+
4+
name: Fleet Analyze
5+
6+
on:
7+
schedule:
8+
- cron: '0 */6 * * *'
9+
workflow_dispatch:
10+
inputs:
11+
goal:
12+
description: 'Path to goal file (or blank for all)'
13+
type: string
14+
default: ''
15+
milestone:
16+
description: 'Milestone ID override'
17+
type: string
18+
default: ''
19+
20+
concurrency:
21+
group: fleet-analyze
22+
cancel-in-progress: false
23+
24+
jobs:
25+
analyze:
26+
runs-on: ubuntu-latest
27+
permissions:
28+
contents: read
29+
issues: write
30+
pull-requests: read
31+
steps:
32+
- uses: actions/checkout@v4
33+
- uses: actions/setup-node@v4
34+
with:
35+
node-version: '22'
36+
- run: npx -y --package=@google/jules-fleet jules-fleet analyze --goal "${{ inputs.goal }}" --milestone "${{ inputs.milestone }}"
37+
env:
38+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39+
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
40+
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
41+
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
42+
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Generated by @google/jules-fleet init
2+
# https://github.com/google-labs-code/jules-sdk
3+
4+
name: Fleet Dispatch
5+
6+
on:
7+
workflow_dispatch:
8+
inputs:
9+
milestone:
10+
description: 'Milestone ID to dispatch (leave empty to dispatch all)'
11+
type: string
12+
required: false
13+
14+
concurrency:
15+
group: fleet-dispatch
16+
cancel-in-progress: false
17+
18+
jobs:
19+
discover:
20+
runs-on: ubuntu-latest
21+
outputs:
22+
milestones: ${{ steps.list.outputs.milestones }}
23+
steps:
24+
- name: Resolve milestones
25+
id: list
26+
env:
27+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
INPUT_MILESTONE: ${{ inputs.milestone }}
29+
run: |
30+
if [ -n "$INPUT_MILESTONE" ]; then
31+
echo "milestones=[\"$INPUT_MILESTONE\"]" >> "$GITHUB_OUTPUT"
32+
else
33+
milestones=$(gh api repos/${{ github.repository }}/milestones --jq '[.[].number | tostring]')
34+
echo "milestones=$milestones" >> "$GITHUB_OUTPUT"
35+
fi
36+
37+
dispatch:
38+
needs: discover
39+
runs-on: ubuntu-latest
40+
strategy:
41+
matrix:
42+
milestone: ${{ fromJSON(needs.discover.outputs.milestones) }}
43+
permissions:
44+
contents: read
45+
issues: write
46+
steps:
47+
- uses: actions/checkout@v4
48+
- uses: actions/setup-node@v4
49+
with:
50+
node-version: '22'
51+
- run: npx -y --package=@google/jules-fleet jules-fleet dispatch --milestone ${{ matrix.milestone }}
52+
env:
53+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54+
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
55+
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
56+
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
57+
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}

.github/workflows/fleet-label.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: Fleet Label PR
2+
on:
3+
pull_request:
4+
types: [opened, edited, synchronize]
5+
6+
permissions:
7+
pull-requests: write
8+
issues: read
9+
10+
jobs:
11+
label_pr:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Check linked issue and apply label/milestone
15+
env:
16+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17+
PR_URL: ${{ github.event.pull_request.html_url }}
18+
REPO: ${{ github.repository }}
19+
run: |
20+
# Use GitHub's own closing keyword resolution to find linked issues
21+
ISSUE_NUMBER=$(gh pr view "$PR_URL" --json closingIssuesReferences --jq '.closingIssuesReferences[0].number // empty')
22+
23+
if [ -z "$ISSUE_NUMBER" ]; then
24+
echo "No closing issue reference found on this PR. Exiting."
25+
exit 0
26+
fi
27+
28+
echo "Found linked issue: #$ISSUE_NUMBER"
29+
30+
# Check if the linked issue has the 'fleet' label
31+
HAS_FLEET=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json labels --jq '[.labels[].name] | any(. == "fleet")')
32+
33+
if [ "$HAS_FLEET" = "true" ]; then
34+
echo "Linked issue has 'fleet' label. Applying 'fleet-merge-ready' to PR."
35+
gh pr edit "$PR_URL" --add-label "fleet-merge-ready"
36+
37+
# Check if linked issue has a milestone and copy it
38+
MILESTONE_TITLE=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json milestone --jq '.milestone.title // empty')
39+
if [ -n "$MILESTONE_TITLE" ]; then
40+
echo "Applying milestone '$MILESTONE_TITLE' to PR."
41+
gh pr edit "$PR_URL" --milestone "$MILESTONE_TITLE"
42+
fi
43+
else
44+
echo "Linked issue does not have 'fleet' label. Ignoring."
45+
fi

.github/workflows/fleet-merge.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Generated by @google/jules-fleet init
2+
# https://github.com/google-labs-code/jules-sdk
3+
4+
name: Fleet Merge
5+
6+
on:
7+
schedule:
8+
- cron: '0 */3 * * *'
9+
workflow_dispatch:
10+
inputs:
11+
mode:
12+
description: 'PR selection mode'
13+
type: choice
14+
options:
15+
- label
16+
- fleet-run
17+
default: 'label'
18+
fleet_run_id:
19+
description: 'Fleet run ID (required for fleet-run mode)'
20+
type: string
21+
default: ''
22+
redispatch:
23+
description: 'Enable smart conflict resolution'
24+
type: boolean
25+
default: true
26+
27+
concurrency:
28+
group: fleet-merge
29+
cancel-in-progress: true
30+
31+
jobs:
32+
merge:
33+
runs-on: ubuntu-latest
34+
permissions:
35+
contents: write
36+
pull-requests: write
37+
issues: write
38+
steps:
39+
- uses: actions/checkout@v4
40+
- uses: actions/setup-node@v4
41+
with:
42+
node-version: '22'
43+
- run: |
44+
REDISPATCH_FLAG="--redispatch"
45+
if [ "${{ inputs.redispatch }}" = "false" ]; then
46+
REDISPATCH_FLAG=""
47+
fi
48+
npx -y --package=@google/jules-fleet jules-fleet merge --mode ${{ inputs.mode || 'label' }} --run-id "${{ inputs.fleet_run_id }}" $REDISPATCH_FLAG
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
JULES_API_KEY: ${{ secrets.JULES_API_KEY }}
52+
FLEET_APP_ID: ${{ secrets.FLEET_APP_ID }}
53+
FLEET_APP_PRIVATE_KEY_BASE64: ${{ secrets.FLEET_APP_PRIVATE_KEY_BASE64 }}
54+
FLEET_APP_INSTALLATION_ID: ${{ secrets.FLEET_APP_INSTALLATION_ID }}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by @google/jules-fleet init
2+
# This workflow scans PRs for overlapping file changes.
3+
name: Conflict Detection
4+
5+
on:
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
pull-requests: read
12+
13+
jobs:
14+
scan-overlaps:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Scan for overlapping changes
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
run: |
25+
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 }}"}'

app/src/main/java/com/leanbitlab/lwidget/AwidgetProvider.kt

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,24 +197,24 @@ class AwidgetProvider : AppWidgetProvider() {
197197

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

202202
val showDate = prefs.getBoolean("show_date", true)
203-
val sizeDate = prefs.getFloat("size_date", 14f)
203+
val sizeDate = prefs.getFloat("size_date", 16f)
204204

205205
val showBattery = prefs.getBoolean("show_battery", true)
206-
val sizeBattery = prefs.getFloat("size_battery", 24f)
207-
val boldBattery = prefs.getBoolean("bold_battery", false)
206+
val sizeBattery = prefs.getFloat("size_battery", 32f)
207+
val boldBattery = prefs.getBoolean("bold_battery", true)
208208

209-
val showTemp = prefs.getBoolean("show_temp", true)
209+
val showTemp = prefs.getBoolean("show_temp", false)
210210
val sizeTemp = prefs.getFloat("size_temp", 18f)
211211
val boldTemp = prefs.getBoolean("bold_temp", false)
212212

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

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

253-
val showStorage = prefs.getBoolean("show_storage", true)
253+
val showStorage = prefs.getBoolean("show_storage", false)
254254
val sizeStorage = prefs.getFloat("size_storage", 14f)
255255

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

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

289-
val bgOpacity = prefs.getFloat("bg_opacity", 100f)
289+
val bgOpacity = prefs.getFloat("bg_opacity", 85f)
290290
val textColorPrimaryIdx = prefs.getInt("text_color_primary_idx", 0)
291291
val textColorSecondaryIdx = prefs.getInt("text_color_secondary_idx", 0)
292292
val bgColorIdx = prefs.getInt("bg_color_idx", 0)
@@ -366,7 +366,7 @@ class AwidgetProvider : AppWidgetProvider() {
366366
}
367367
}
368368

369-
val showOutline = prefs.getBoolean("show_outline", true)
369+
val showOutline = prefs.getBoolean("show_outline", false)
370370
val outlineColor = resolveOutlineColor(outlineColorIdx)
371371
views.setImageViewResource(R.id.widget_outline, R.drawable.widget_bg_outline)
372372
views.setViewVisibility(R.id.widget_outline, if (showOutline) android.view.View.VISIBLE else android.view.View.GONE)
@@ -753,12 +753,19 @@ class AwidgetProvider : AppWidgetProvider() {
753753
// Calculate cumulative Y positions for each visible item
754754
val rightDp = context.resources.displayMetrics.density
755755
var cumulativeTopDp = 24f // Starting top margin from top of widget
756+
var isFirstVisible = true
756757
for (entry in rightStack) {
757758
if (entry.isVisible) {
759+
if (isFirstVisible) {
760+
// Compensate for font intrinsic top padding (matches left side logic)
761+
val intrinsicGap = entry.size * 0.18f
762+
cumulativeTopDp = maxOf(0f, 24f - intrinsicGap)
763+
isFirstVisible = false
764+
}
758765
val topPaddingPx = (cumulativeTopDp * rightDp).toInt()
759766
views.setViewPadding(entry.viewId, 0, topPaddingPx, 0, 0)
760767
// Advance by this item's height + small gap
761-
val itemHeightDp = entry.size * 1.2f // approximate line height
768+
val itemHeightDp = entry.size * 1.15f // approximate line height
762769
cumulativeTopDp += itemHeightDp + 2f
763770
}
764771
}

0 commit comments

Comments
 (0)