Compare commits
No commits in common. "main" and "v0.3.2" have entirely different histories.
4 changed files with 16 additions and 105 deletions
54
AGENTS.md
54
AGENTS.md
|
|
@ -1,54 +0,0 @@
|
||||||
# Decky agent notes
|
|
||||||
|
|
||||||
## Project
|
|
||||||
|
|
||||||
- The active app is `app/`: Tauri 2 + Svelte 5 + TypeScript. The older .NET
|
|
||||||
projects under `src/` and `tests/` are reference code, not the product.
|
|
||||||
- Decky is a compact, Nextcloud-inspired desktop client for Nextcloud Deck.
|
|
||||||
Preserve its dark native title bar, horizontal/vertical views, drag-and-drop,
|
|
||||||
compact cards, collapsible sidebar, and footer-free layout.
|
|
||||||
- Background sync begins after 10 seconds idle and repeats every 30 seconds. It
|
|
||||||
must pause during edits, drags, loading, modals, and while the window is hidden.
|
|
||||||
- Never store or commit Nextcloud credentials. Use an app password and the OS
|
|
||||||
credential store. Live-instance tests require the user to enter credentials.
|
|
||||||
|
|
||||||
## Nextcloud API compatibility
|
|
||||||
|
|
||||||
- Client code and tests are in `app/src/lib/deck-api.ts` and
|
|
||||||
`app/src/lib/deck-api.test.ts`.
|
|
||||||
- Support both documented `index.php/apps/deck/api/v1.0/` and rewrite-friendly
|
|
||||||
`apps/deck/api/v1.0/` paths.
|
|
||||||
- Preserve complete card fields on updates, including color and object/string
|
|
||||||
owner handling. Keep the tested cross-stack card-move fallback.
|
|
||||||
- Stack reorder uses Deck's OCS reorder endpoint and verifies persisted order.
|
|
||||||
- Respect board permissions before exposing edit/manage/delete controls.
|
|
||||||
|
|
||||||
## Validation
|
|
||||||
|
|
||||||
From `app/`, run `npm ci`, `npm run check`, `npm test`, and `npm run build`.
|
|
||||||
Build Windows installers on this Windows machine; the Unraid Forgejo Docker
|
|
||||||
runner only validates the web client via `.forgejo/workflows/validate.yml`.
|
|
||||||
|
|
||||||
## Versions and releases
|
|
||||||
|
|
||||||
- Installed apps update from signed Forgejo Release assets, never from Git.
|
|
||||||
- A released version/tag is immutable. Always increment the semantic version;
|
|
||||||
never republish or replace assets for an existing version.
|
|
||||||
- Use `scripts/Set-Version.ps1` to synchronize npm, Cargo, Tauri, and the browser
|
|
||||||
fallback. Commit and push source to `main` before publishing the release.
|
|
||||||
- Build/sign with `scripts/Prepare-Release.ps1`. Generated files live under
|
|
||||||
`artifacts/release/vX.Y.Z/` and stay out of Git.
|
|
||||||
- Publish by double-clicking `scripts/Publish-DeckyRelease.cmd` or by invoking
|
|
||||||
`scripts/Publish-ForgejoRelease.ps1`. The publisher creates the tag/release,
|
|
||||||
uploads the installer/signature, commits `releases/latest.json` to `main`, and
|
|
||||||
automatically fast-forwards the local checkout to that metadata commit.
|
|
||||||
- The publisher requires a clean `main` that exactly matches `origin/main`, so
|
|
||||||
commit and push source first. LF-to-CRLF messages on Windows are warnings,
|
|
||||||
not failures.
|
|
||||||
- Forgejo: `https://git.elijahkuntz.com/Elijah/Decky`. A publishing PAT needs
|
|
||||||
`write:repository`; never commit or print it.
|
|
||||||
- The permanent Tauri updater key is outside the repository at
|
|
||||||
`%USERPROFILE%\.tauri\decky.key` with its password beside it. Never expose,
|
|
||||||
replace, or regenerate this key after releases have shipped.
|
|
||||||
|
|
||||||
See `app/UPDATES.md` for the complete release procedure.
|
|
||||||
|
|
@ -73,6 +73,7 @@ current PowerShell process and run:
|
||||||
$env:FORGEJO_PAT = 'paste-token-for-this-session'
|
$env:FORGEJO_PAT = 'paste-token-for-this-session'
|
||||||
powershell -ExecutionPolicy Bypass -File .\scripts\Publish-ForgejoRelease.ps1 -Version 0.3.0 -Notes "Board and stack management"
|
powershell -ExecutionPolicy Bypass -File .\scripts\Publish-ForgejoRelease.ps1 -Version 0.3.0 -Notes "Board and stack management"
|
||||||
Remove-Item Env:FORGEJO_PAT
|
Remove-Item Env:FORGEJO_PAT
|
||||||
|
git pull --ff-only
|
||||||
```
|
```
|
||||||
|
|
||||||
For an interactive, double-clickable option, run:
|
For an interactive, double-clickable option, run:
|
||||||
|
|
@ -85,12 +86,11 @@ It bypasses PowerShell's script policy only for the publisher process, prompts
|
||||||
for the version and a hidden personal access token, and leaves the window open
|
for the version and a hidden personal access token, and leaves the window open
|
||||||
so any error can be read. The token is not saved.
|
so any error can be read. The token is not saved.
|
||||||
|
|
||||||
The publisher first verifies that the working tree is clean and local `main`
|
The publisher creates the `v0.3.0` Forgejo release/tag at `main`, uploads the
|
||||||
exactly matches `origin/main`. It then creates the `v0.3.0` Forgejo release/tag,
|
installer, signature, and metadata, then commits the tracked
|
||||||
uploads the installer, signature, and metadata, and commits the tracked
|
`releases/latest.json` through the Forgejo API. The final pull synchronizes that
|
||||||
`releases/latest.json` through the Forgejo API. Finally, it automatically
|
small metadata commit locally. Existing Decky installations then discover the
|
||||||
fast-forwards local `main` to that metadata commit. Existing Decky installations
|
release through Settings.
|
||||||
then discover the release through Settings.
|
|
||||||
|
|
||||||
## Forgejo Actions
|
## Forgejo Actions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"version": "0.3.2",
|
"version": "0.3.1",
|
||||||
"notes": "Removed the bottom status bar, moved the updated time beside Refresh, and cleaned malformed text encoding.",
|
"notes": "Automatic idle-aware background refresh for boards, stacks, and cards.",
|
||||||
"pub_date": "2026-07-20T16:13:33.7170490+00:00",
|
"pub_date": "2026-07-20T15:55:49.5091194+00:00",
|
||||||
"platforms": {
|
"platforms": {
|
||||||
"windows-x86_64": {
|
"windows-x86_64": {
|
||||||
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVTSHZBY0NPTW9uREMyYUlZNUJnYzhqRHRlTE1qeDZCYlZtVXRGRDZtZER5V2p1V3ZBdXprVndkZ3FqNURzQitoUG1ZWFdFQytxRFFzQ1BMNnJnVE10ZlhCYm5UQk9NTFFFPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzg0NTY0MDEyCWZpbGU6RGVja3lfMC4zLjJfeDY0LXNldHVwLmV4ZQpLOGZ4TXp6V0xYalp6czNDbitleVhBSVlrZHNLT0ZQSmhiTjFGeXlNTUVEYy8vSS9JdlZwQUdiNWdOL0NvcXVFcTVJWDhXWXZwQnhlUnh2Z0xER3dEdz09Cg==",
|
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUlVTSHZBY0NPTW9uREdMTkg2RWVNeU53anpNRy9SYy9LS3RnS3I5a0FSVzJrRVZ5Y1NjdHlId2VaRi9YcnNyZnF3YjRIT3VuRVVNOGt2Zk8wWmZObGpYWmFJc2xpRENVOEFnPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNzg0NTYyOTQ4CWZpbGU6RGVja3lfMC4zLjFfeDY0LXNldHVwLmV4ZQpDeEphcVV0T2hkc09kYUJxak14UnU1N1h6L3dJTWhDV2Rqa3Nhc21sTWxuS0VYWW5scEhYakx5MDJ5bVdmbmRkTnphWjdib3BHTCtYVm5yMGZldHdCQT09Cg==",
|
||||||
"url": "https://git.elijahkuntz.com/Elijah/Decky/releases/download/v0.3.2/Decky_0.3.2_x64-setup.exe"
|
"url": "https://git.elijahkuntz.com/Elijah/Decky/releases/download/v0.3.1/Decky_0.3.1_x64-setup.exe"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,35 +12,6 @@ param(
|
||||||
)
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = 'Stop'
|
$ErrorActionPreference = 'Stop'
|
||||||
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
|
||||||
$releaseDirectory = Join-Path $repositoryRoot "artifacts\release\v$Version"
|
|
||||||
$latestJsonPath = Join-Path $releaseDirectory 'latest.json'
|
|
||||||
if (-not (Test-Path -LiteralPath $latestJsonPath)) { throw "Run Prepare-Release.ps1 first: $latestJsonPath is missing." }
|
|
||||||
|
|
||||||
function Invoke-GitCommand {
|
|
||||||
param([Parameter(Mandatory)][string[]]$ArgumentList)
|
|
||||||
$output = @(& git -C $repositoryRoot @ArgumentList 2>&1)
|
|
||||||
if ($LASTEXITCODE) {
|
|
||||||
throw "git $($ArgumentList -join ' ') failed: $($output -join [Environment]::NewLine)"
|
|
||||||
}
|
|
||||||
return $output
|
|
||||||
}
|
|
||||||
|
|
||||||
$branch = ((Invoke-GitCommand @('rev-parse', '--abbrev-ref', 'HEAD')) | Select-Object -Last 1).Trim()
|
|
||||||
if ($branch -ne 'main') { throw "Releases must be published from main; the current branch is '$branch'." }
|
|
||||||
|
|
||||||
$workingChanges = @(Invoke-GitCommand @('status', '--porcelain'))
|
|
||||||
if ($workingChanges.Count) {
|
|
||||||
throw "Commit or discard all source changes before publishing:`n$($workingChanges -join [Environment]::NewLine)"
|
|
||||||
}
|
|
||||||
|
|
||||||
Invoke-GitCommand @('fetch', 'origin', 'main') | Out-Null
|
|
||||||
$localHead = ((Invoke-GitCommand @('rev-parse', 'HEAD')) | Select-Object -Last 1).Trim()
|
|
||||||
$remoteHead = ((Invoke-GitCommand @('rev-parse', 'origin/main')) | Select-Object -Last 1).Trim()
|
|
||||||
if ($localHead -ne $remoteHead) {
|
|
||||||
throw 'Local main does not exactly match origin/main. Pull/rebase or push the source before publishing.'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (-not $Token) {
|
if (-not $Token) {
|
||||||
Write-Host 'A Forgejo personal access token is required to create the release.' -ForegroundColor Cyan
|
Write-Host 'A Forgejo personal access token is required to create the release.' -ForegroundColor Cyan
|
||||||
Write-Host 'The token is used only by this process and is not saved by Decky.' -ForegroundColor DarkGray
|
Write-Host 'The token is used only by this process and is not saved by Decky.' -ForegroundColor DarkGray
|
||||||
|
|
@ -49,6 +20,11 @@ if (-not $Token) {
|
||||||
}
|
}
|
||||||
if (-not $Token) { throw 'No Forgejo personal access token was entered.' }
|
if (-not $Token) { throw 'No Forgejo personal access token was entered.' }
|
||||||
|
|
||||||
|
$repositoryRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$releaseDirectory = Join-Path $repositoryRoot "artifacts\release\v$Version"
|
||||||
|
$latestJsonPath = Join-Path $releaseDirectory 'latest.json'
|
||||||
|
if (-not (Test-Path -LiteralPath $latestJsonPath)) { throw "Run Prepare-Release.ps1 first: $latestJsonPath is missing." }
|
||||||
|
|
||||||
$headers = @{ Authorization = "token $Token"; Accept = 'application/json' }
|
$headers = @{ Authorization = "token $Token"; Accept = 'application/json' }
|
||||||
$apiRoot = "$($ForgejoBaseUrl.TrimEnd('/'))/api/v1/repos/$Repository"
|
$apiRoot = "$($ForgejoBaseUrl.TrimEnd('/'))/api/v1/repos/$Repository"
|
||||||
$tag = "v$Version"
|
$tag = "v$Version"
|
||||||
|
|
@ -106,14 +82,3 @@ $contentBody = @{
|
||||||
if ($sha) { $contentBody.sha = $sha }
|
if ($sha) { $contentBody.sha = $sha }
|
||||||
Invoke-RestMethod -Method Put -Uri "$apiRoot/contents/releases/latest.json" -Headers $headers -ContentType 'application/json' -Body ($contentBody | ConvertTo-Json) | Out-Null
|
Invoke-RestMethod -Method Put -Uri "$apiRoot/contents/releases/latest.json" -Headers $headers -ContentType 'application/json' -Body ($contentBody | ConvertTo-Json) | Out-Null
|
||||||
Write-Host "Published Decky $Version and updated releases/latest.json."
|
Write-Host "Published Decky $Version and updated releases/latest.json."
|
||||||
|
|
||||||
Invoke-GitCommand @('fetch', 'origin', 'main') | Out-Null
|
|
||||||
$publishedHead = ((Invoke-GitCommand @('rev-parse', 'origin/main')) | Select-Object -Last 1).Trim()
|
|
||||||
if ($publishedHead -ne $localHead) {
|
|
||||||
$mergeBase = ((Invoke-GitCommand @('merge-base', $localHead, $publishedHead)) | Select-Object -Last 1).Trim()
|
|
||||||
if ($mergeBase -ne $localHead) {
|
|
||||||
throw 'The release was published, but origin/main also changed independently. Fetch and reconcile it manually.'
|
|
||||||
}
|
|
||||||
Invoke-GitCommand @('merge', '--ff-only', 'origin/main') | Out-Null
|
|
||||||
}
|
|
||||||
Write-Host 'Local main is synchronized with the Forgejo release metadata commit.'
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue