Files
chatSummaries/.gitea/workflows/release.yml
T
lyuksovannyy 196da742de Implement Chat Summaries plugin
Replace the sample plugin with an AI chat summarizer that renders its
output as a native RichMessage injected into the chat.

Summarization pipeline:
- Fetch chat/topic history via paginated TL requests.
- Send a system prompt, the user's instructions and an anonymized JSON
  transcript as three separate roles. Only message text and attachment
  names leave the device; senders and message ids are replaced by
  indices, and out-of-range reply parents are included with negative ids
  so replies keep their context.
- Stream the response over SSE, reading reasoning from reasoning_content,
  reasoning or inline <think> tags.
- Substitute the model's {userN}/{msgN} placeholders back into real names
  and deep links. Placeholders are used instead of Markdown links because
  a half-streamed link renders as broken literal text.

Rendering:
- Compile Markdown into TL_iv page blocks (headings, lists, quotes, code,
  dividers, inline styles) since the app's own converter works off
  Android Spanned spans rather than Markdown source.
- Show progress stages immediately on click, animate reasoning while it
  streams, then collapse it into a tappable details block.
- Attribute the card to a client-side mock sender and insert it directly
  after the newest analyzed message, scrolling it into view.

Persistence:
- Store summaries in SQLite keyed by (dialog, topic, anchor) and
  re-inject them when the chat is reopened.

Also add tools/release.py and a Gitea workflow that builds, verifies and
publishes dist/<id>.plugin to the Releases tab, and extend
tools/verify_bundle.py to 104 offline checks covering the transcript,
streaming, rendering, injection and storage behaviour.
2026-09-12 23:52:15 +02:00

77 lines
2.7 KiB
YAML

name: Publish plugin
# Builds dist/<id>.plugin and publishes it to the Releases tab.
#
# Triggers:
# push a v* tag -> release named after that tag
# manual dispatch -> release named v<version from plugin.json>
#
# dist/ is gitignored, so the artifact is always built here rather than
# committed. The build uses --release because --dev embeds absolute paths from
# whichever machine produced it.
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out sources
uses: actions/checkout@v4
- name: Validate plugin metadata and sources
run: python3 tools/bundle.py --check
- name: Build release bundle
id: build
run: |
set -eu
python3 tools/bundle.py --release
plugin_id=$(python3 -c "import json; print(json.load(open('plugin.json'))['id'])")
version=$(python3 -c "import json; print(json.load(open('plugin.json'))['version'])")
artifact="dist/${plugin_id}.plugin"
test -s "$artifact"
echo "artifact=${artifact}" >> "$GITHUB_OUTPUT"
echo "asset_name=${plugin_id}.plugin" >> "$GITHUB_OUTPUT"
echo "version=${version}" >> "$GITHUB_OUTPUT"
echo "built ${artifact} ($(wc -c < "$artifact") bytes)"
- name: Verify the built bundle
# Executes the bundle against faked SDK modules and asserts the
# plugin's observable behaviour. A build that fails this is not
# publishable, so this gates the upload.
run: python3 tools/verify_bundle.py "${{ steps.build.outputs.artifact }}"
- name: Resolve release tag
id: tag
run: |
set -eu
if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
tag="${GITHUB_REF_NAME}"
else
tag="v${{ steps.build.outputs.version }}"
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "publishing as ${tag}"
- name: Publish release and upload plugin
env:
# Org-level secret holding a user token with write:repository scope.
# Not using a `||` fallback to GITEA_TOKEN: Gitea's expression engine
# supports only always(), so the operator would not evaluate.
GITEA_TOKEN: ${{ secrets.API_TOKEN }}
run: |
python3 tools/release.py \
--api "${{ github.server_url }}/api/v1/repos/${{ github.repository }}" \
--tag "${{ steps.tag.outputs.tag }}" \
--artifact "${{ steps.build.outputs.artifact }}" \
--asset-name "${{ steps.build.outputs.asset_name }}" \
--commitish "${{ github.sha }}"