Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
18 changes: 0 additions & 18 deletions .dockerignore

This file was deleted.

10 changes: 0 additions & 10 deletions .env.example

This file was deleted.

19 changes: 10 additions & 9 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
name: Bug report
description: Report a reproducible problem in Link or LinkAgent
description: Report a reproducible problem in Smallink
title: "[Bug]: "
labels:
- bug
body:
- type: markdown
attributes:
value: |
Thanks for helping improve Link. Remove tokens, private paths, and raw conversation content before attaching logs or screenshots.
Thanks for helping improve Smallink. Remove tokens, private paths, and raw conversation content before attaching logs or screenshots.
- type: dropdown
id: component
attributes:
label: Component
options:
- Link Web / platform API
- LinkAgent
- Codex connector
- Web crawler
- Docker / deployment
- macOS desktop client
- Local sidecar / API
- Agent runtime and tools
- Memory and data governance
- MineM application / connector
- Automation and run center
- Documentation
validations:
required: true
- type: input
id: version
attributes:
label: Version
placeholder: 0.2.1 Developer Preview or commit SHA
placeholder: App version or commit SHA
validations:
required: true
- type: textarea
Expand Down Expand Up @@ -55,7 +56,7 @@ body:
id: environment
attributes:
label: Environment
placeholder: macOS version, CPU architecture, Docker version, browser
placeholder: macOS version, CPU architecture, installation type
validations:
required: true
- type: textarea
Expand Down
19 changes: 10 additions & 9 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
name: Feature request
description: Propose a connector or product capability grounded in a real workflow
description: Propose a Smallink capability grounded in a real workflow
title: "[Feature]: "
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
Link is building the data intake foundation first. A strong proposal explains the user problem, source boundary, and observable result before suggesting implementation details.
A strong proposal explains the user problem, capability boundary, source data, permissions, and observable result before suggesting implementation details.
- type: textarea
id: problem
attributes:
Expand All @@ -27,19 +27,20 @@ body:
attributes:
label: Product area
options:
- New connector
- LinkAgent desktop experience
- Raw data browsing
- Web crawler
- Deployment and operations
- Agent and multi-agent collaboration
- Memory and data governance
- New application or connector
- Desktop interaction
- Automation and run center
- Model provider and tools
- Developer experience
validations:
required: true
- type: textarea
id: source
attributes:
label: Source and authorization boundary
description: For connector ideas, explain where the data lives and what the user should authorize.
label: Data source and authorization boundary
description: Explain where the data lives, what Smallink should access, and what the user should authorize.
- type: textarea
id: evidence
attributes:
Expand Down
9 changes: 5 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

## 验证

- [ ] `npm run lint`
- [ ] `npm run build`
- [ ] LinkAgent 前端构建
- [ ] LinkAgent Rust 测试
- [ ] `pytest tests -q`
- [ ] `npm --prefix surfaces/gui test`
- [ ] `npm --prefix surfaces/gui run build`
- [ ] `npm --prefix surfaces/gui run e2e`
- [ ] `cargo check --manifest-path surfaces/gui/src-tauri/Cargo.toml`

## 数据与隐私

Expand Down
68 changes: 45 additions & 23 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
name: CI
# Smallink CI — the Python suite, GUI unit tests, and the hermetic
# Playwright e2e suite (mocked /v1 + WS; no model or network needed).

on:
push:
branches: [main]
pull_request:
name: CI

permissions:
contents: read
on: [push, pull_request]

jobs:
platform:
pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[messaging,dev]"
- name: Test
run: pytest tests -q
- name: Version consistency
run: python scripts/check_versions.py

gui-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run build
cache-dependency-path: surfaces/gui/package-lock.json
- name: npm ci
working-directory: surfaces/gui
run: npm ci
- name: Unit tests
working-directory: surfaces/gui
run: npm test
- name: Production dependency audit
working-directory: surfaces/gui
run: npm audit --omit=dev

link-agent:
runs-on: macos-14
defaults:
run:
working-directory: link-agent-client
gui-e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
node-version: 20
cache: npm
cache-dependency-path: link-agent-client/package-lock.json
- uses: dtolnay/rust-toolchain@stable
- run: npm ci
- run: npm run build
- run: cargo test --manifest-path src-tauri/Cargo.toml
cache-dependency-path: surfaces/gui/package-lock.json
- name: npm ci
working-directory: surfaces/gui
run: npm ci
- name: Install Playwright browsers
working-directory: surfaces/gui
run: npx playwright install --with-deps chromium
- name: e2e
working-directory: surfaces/gui
run: npm run e2e
153 changes: 153 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Desktop release builds — macOS Apple Silicon (.dmg).
#
# CI calls the SAME packaging/build_dmg.sh script developers run locally; this file only
# provisions the toolchain (Node, Rust, a Python venv at .venv with PyInstaller) and
# publishes the result.
#
# Triggers:
# - tag push `v*` → builds all targets and attaches them to a DRAFT GitHub Release
# (review, then publish by hand).
# - manual run → builds and uploads workflow artifacts only (no release).
#
# Each installer is uploaded twice: once with its versioned name (archive) and once with a
# stable name (Smallink-macos-arm64.dmg, …) so the website can link to
# github.com/<repo>/releases/latest/download/<stable-name>
# and never need updating. Add Windows back only after packaging/build_windows.ps1 exists
# in the repository and is covered by a local or CI smoke test.
#
# macOS signing + notarization: Tauri's bundler handles both during `tauri build` when the
# APPLE_* env vars are present (import cert → sign app + sidecar with hardened runtime →
# notarize via notarytool → staple). Driven by repo secrets:
# APPLE_CERTIFICATE base64 .p12 (Developer ID Application cert + key)
# APPLE_CERTIFICATE_PASSWORD the .p12 export password
# APPLE_SIGNING_IDENTITY e.g. "Developer ID Application: Name (TEAMID)"
# APPLE_API_KEY_CONTENT base64 App Store Connect API .p8 (notarytool)
# APPLE_API_KEY the API key id
# APPLE_API_ISSUER the API issuer id
# When the secrets are absent (forks, scratch runs) the build degrades to unsigned —
# installable via `xattr -cr`.

name: Release

on:
push:
tags: ["v*", "app-v*"]
workflow_dispatch:

defaults:
run:
shell: bash

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest # Apple Silicon
slug: macos-arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: surfaces/gui/package-lock.json

- uses: dtolnay/rust-toolchain@stable

- name: Install native build dependencies
run: brew install cmake

- uses: Swatinem/rust-cache@v2
with:
workspaces: surfaces/gui/src-tauri

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Set up the sidecar venv (.venv)
# The build scripts expect a venv at .venv with the package + PyInstaller.
# typer/tzdata are build-time-only (PyInstaller walks mcp.cli, which needs typer;
# tzdata ships zoneinfo for Windows). aisuite installs like any other dependency
# (git-pinned in pyproject.toml).
run: |
python -m venv .venv
VPY=.venv/bin/python
"$VPY" -m pip install --upgrade pip
"$VPY" -m pip install -e . pyinstaller typer tzdata
"$VPY" -c "import aisuite, smallink" # fail fast if either import breaks

- name: npm ci
working-directory: surfaces/gui
run: npm ci

- name: Validate release version
run: python scripts/check_versions.py

- name: Build .dmg
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY_CONTENT }}
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
run: |
# Unset empty APPLE_* vars so runs without secrets stay cleanly unsigned
# (Tauri treats a present-but-empty var as a config error).
for v in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_API_KEY APPLE_API_ISSUER; do
[ -n "$(eval echo "\${$v:-}")" ] || unset "$v"
done
if [ -n "${APPLE_API_KEY_CONTENT:-}" ]; then
echo "$APPLE_API_KEY_CONTENT" | base64 -d > "$RUNNER_TEMP/AuthKey.p8"
export APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey.p8"
fi
unset APPLE_API_KEY_CONTENT
bash packaging/build_dmg.sh

- name: Stage artifacts (versioned + stable names)
run: |
mkdir -p out
BUNDLE=surfaces/gui/src-tauri/target/release/bundle
cp "$BUNDLE"/dmg/*.dmg out/
cp "$BUNDLE"/dmg/*.dmg out/Smallink-${{ matrix.slug }}.dmg
ls -la out

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.slug }}
path: out/*
if-no-files-found: error

release:
if: startsWith(github.ref, 'refs/tags/v')
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4

- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true

- name: Validate release version
run: |
TAG="${GITHUB_REF_NAME}"
CONF_VERSION=$(python3 -c "import json; print(json.load(open('surfaces/gui/src-tauri/tauri.conf.json'))['version'])")
if [ "${TAG#v}" != "$CONF_VERSION" ]; then
echo "::error::tag $TAG != tauri.conf.json version $CONF_VERSION — bump the config before tagging"
exit 1
fi

- uses: softprops/action-gh-release@v2
with:
draft: true
files: dist/*
generate_release_notes: true
Loading
Loading