Commit Graph
4418 Commits
Author SHA1 Message Date
RainbowBird 51ee053bc1 fix(api-server): preserve config cache namespace 2026-09-17 01:37:48 +08:00
RainbowBird efecc99a01 fix(api-server): complete cache expiry cleanup and shared keys 2026-09-17 01:33:33 +08:00
xy 6d3fd7a605 fix(stage-ui): hide browser local transcription provider until its settings page exists (#2558) 2026-09-17 02:14:28 +09:00
蓝莓🫐 9d4398eadd fix(stage-pages): keep required field labels on one line (#2561) 2026-09-17 02:13:00 +09:00
Neko b4686b4dfb chore(.agents/skills): clarify attachment uploads and screenshot readiness (#2564) 2026-09-17 02:11:54 +09:00
RainbowBird 72999dda75 refactor(api-server): centralize Redis cache expiry policy (#2563) 2026-09-16 17:02:35 +00:00
RainbowBird 83b8b9afd4 fix(api-server): expire Flux balance cache after one minute (#2562) 2026-09-17 00:39:34 +08:00
凌莞~(=^▽^=) 1b019c32b3 fix(stage-ui): persist onboarding provider config through synced actions (#2557)
## Description

<!-- Please insert your description here and especially provide info
about the "what" this PR is solving -->

当首次启动桌面版,初始化选择 “OpenAI 兼容” provider 的时候,会出现输入了我自己的 base url 和 api key
之后,无论是否勾选允许向第一个模型发送请求来探测可用性,都会提示 找不到可用模型 的情况,但是实际上 apikey 和 base url
都没有问题,而且也正常发送了获取模型列表的 hello 的请求。返回后填写的内容被重置

问题出在 onbording 保存配置的时候,写入写到了 computed 的临时对象上,而且桌面版配置向导的独立窗口
`synced-leader` 为 false

## Linked Issues

<!-- Optional, if you have any -->

看起来暂时没人提

## Additional Context

<!-- e.g. is there anything you'd like reviewers to focus on? -->
2026-09-16 15:06:00 +08:00
leafyy 827d22502e feat(plugin-host): import extensions from folders (#2506)
AIRI desktop could load Extensions that were already present on disk,
but users could not safely add an Extension folder. This PR completes
Extension Manifest v2 and adds a review-first folder import flow. An
imported Extension remains disabled and unloaded until the user
explicitly enables and loads it.

The design was informed by the incomplete `claude-code-plugin`
experiment and the Agent Activity Extension work tracked in #2507.

## User flow

1. Select an Extension folder in Plugin Host Devtools.
2. Review its identity, version, runtime, entrypoints, permissions, Kit
declarations, file count, and total size.
3. Confirm the import.
4. Enable and load the Extension when it is ready to run.
5. Disable and unload it to stop its runtime session.

## What changed

### Extension Manifest v2

- Add a strict schema for identity, version, AIRI compatibility,
runtimes, entrypoints, permissions, and Kit declarations.
- Reject unknown fields, duplicate runtime or Kit declarations, unsafe
Extension ids, missing entrypoints, and invalid semantic versions.
- Check `engines.airi` and the current runtime before importing an
Extension entrypoint.
- Keep Plugin Host transfer types in the runtime-neutral
`@proj-airi/stage-shared/plugin-host` boundary.

### Folder import

- Add separate prepare and commit steps so package code cannot run
during review.
- Bind the reviewed manifest to a package fingerprint and revalidate the
source before and after copying it.
- Reject symbolic links, absolute entrypoints, entrypoints outside the
package, duplicate Extension ids, and source changes after review.
- Limit packages to 10,000 entries and 512 MiB and manifests to 1 MiB.
Hash and copy file data with streams.
- Copy into `.imports` staging and publish the package with an atomic
rename.
- Record the validated committed entry directly in the registry after a
successful import.
- Retain the macOS security-scoped bookmark from folder selection
through commit.
- Wait for an active import during Host shutdown so no managed-directory
write outlives the Host.

### Desktop controls

- Add Devtools actions for importing an Extension folder.
- Add combined **Enable and load** and **Disable and unload** actions
that model real user behavior.
- Add English and Simplified Chinese strings for the new controls and
import review.

## Scope

This PR defines Kit declarations as manifest data. Extension-hosted Kit
routing, Provider and Consumer lifecycle, revocable clients, and
dependency activation order are isolated in draft PR #2549.

## Verification

- GitHub CI passed: unit tests, type checks, lint, provenance checks,
and all configured builds.
- Focused Plugin SDK core, directory importer, and Electron Plugin Host
tests: 86 passed.
- Stage UI Plugin Host store tests: 8 passed.
- `pnpm typecheck`: 52 workspace tasks passed.
- `pnpm lint`: passed with 646 existing repository warnings and no
errors.
- `sem diff --staged --no-cosmetics -v --file-exts .ts .tsx`: the final
shutdown batch analyzed 113 entities; its JSON report contained no
diagnostics.
- The importer shutdown regression failed before the fix and passed
after it.

## Visual change

| Before | After |
|---|---|
| Extension folder import was unavailable. | ![Plugin Host Extension
folder import
review](https://github.com/user-attachments/assets/813b820e-4663-473c-965c-b29bbcfb2601)
|
2026-09-16 11:31:04 +08:00
Weathercoldandgithub-actions[bot] 3da3cf8154 chore(nix): update pnpmDeps hash (#2553)
Auto-generated by CI to keep Nix pnpmDeps hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-15 13:59:27 +00:00
RainbowBirdandNeko Ayaka e1957d2832 feat(client): support Responses API with user-provided API keys (#2477)
Co-authored-by: Neko Ayaka <neko@ayaka.moe>
2026-09-15 21:51:01 +08:00
Columbina 7cfd395561 fix(stage-pages): avoid duplicate speech voice loads (#2543) 2026-09-15 09:59:14 +08:00
Weathercoldandgithub-actions[bot] a5716a8370 chore(nix): update pnpmDeps hash (#2548)
Auto-generated by CI to keep Nix pnpmDeps hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-14 19:59:02 +00:00
Neko 7eec25eeeb chore(lint): add eslint-plugin-slop (#2544) 2026-09-15 03:49:40 +08:00
Columbina 334f8b9c6c fix(stage-ui): synchronize speech settings across windows (#2467) 2026-09-15 02:27:18 +08:00
RainbowBird 1a79f8b1ca fix(stage-layouts): avoid Safari Form Assistant (#2461) 2026-09-14 19:45:07 +08:00
Neko 9f30a1977e fix(stage-ui): apply Apple Speech locale in hearing settings (#2540) 2026-09-14 13:11:33 +08:00
Columbina 54e49766d8 fix(stage-pages): load speech provider voices after configuration updates (#2525) 2026-09-14 13:09:07 +08:00
이윤진(Lee Yunjin) 42e3e9e857 fix(stage-tamagotchi): keep controls island open on native Wayland (#2522) 2026-09-14 00:34:45 +08:00
Neko a75b031ccc feat(ui,stage-ui): add bidirectional swipe actions for conversations (#2536) 2026-09-14 00:33:34 +08:00
Lulu 00c6867b7f refactor(api): restore Stripe product catalog as Flux pack source (#2533) 2026-09-12 07:33:17 -07:00
Lovehsigure_520 553d8a0da4 feat(auth): accept configured native Google ID token audiences (#2518) 2026-09-12 11:44:16 +00:00
RainbowBird 41ee5ee5c8 docs: place ADRs under ai/adr directories 2026-09-12 19:25:43 +08:00
RainbowBird 827b692b15 docs: keep ADRs in the main repository 2026-09-12 19:23:23 +08:00
Weathercoldandgithub-actions[bot] 938c9d6b88 chore(nix): update assets hash (#2532)
Auto-generated by CI to keep Nix asset hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-12 10:12:36 +00:00
RainbowBird 1d27dc7cdf fix(stage-web): cache canonical app shell for payment returns (#2531)
Payment completed and Flux was credited, but returning from Stripe
showed `ERR_FAILED`. Edge reported that the service worker replayed a
redirected response for a navigation request. Cloudflare redirects
`/index.html` to `/`.

Precache the canonical root URL and use it as the navigation fallback.
The new cache key also avoids reusing the old redirected app shell.

Validation: generated a service worker with the installed Workbox
version and verified both its precache entry and navigation handler use
`./`; ESLint passed. Production payment credited 500 Flux, and bypassing
the service worker restored the page. Normal-cache production
verification follows deployment.
2026-09-12 18:00:48 +08:00
37c837e502 refactor(api): extract payment CORE to support other payment providers [1/2] (#2335)
## Why

Stripe checkout used Stripe-only tables. This extracts a shared payment
CORE. New checkout writes `payment_order`. Old Stripe tables stay so
in-progress Sessions can still settle.

This PR is [1/2]. [#2368](https://github.com/moeru-ai/airi/pull/2368) is
[2/2]. That PR archives leftover Stripe tables after in-progress
Sessions finish or expire.

## Changes

- Add `payment_order` and `provider_account`.
- Copy `stripe_checkout_session` into `payment_order`.
- Copy `stripe_customer` into `provider_account`.
- Keep `stripe_*` tables and `user_flux.stripe_customer_id`.
- New checkout writes `payment_order` and stores
`metadata.payment_order_id`.
- Webhook resolves new Sessions by `metadata.payment_order_id`.
- Webhook resolves older Sessions by `provider_order_id`, then by a
leftover `stripe_checkout_session` row.
- That leftover-row lookup covers Sessions opened before this deploy,
and rows written while 0023 runs.
[#2368](https://github.com/moeru-ai/airi/pull/2368) deletes it after
those Sessions finish or expire.

## Test plan

- [x] `pnpm exec vitest run
server/apps/api/src/services/domain/payment/tests/payment.test.ts
server/apps/api/src/routes/stripe`
- [x] `pnpm -F @proj-airi/api-server typecheck`
- [x] `git diff --check`

## Visual changes

No user-visible changes.

## Open: settle after account deletion

Account deletion stamps `payment_order.deletedAt`. A Checkout Session
that is still open can still pay after that stamp. This PR keeps `main`
behavior. `settle` loads the row by id, including a soft-deleted row,
then marks it `paid` and credits Flux.

Follow-up policy: if `deletedAt` is set, skip. Do not update the archive
row. Do not credit Flux. Do not insert a live `provider_account`. Stripe
remains the payment record. Skip matches the soft-delete rule: a deleted
row is gone, not write it again.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: RainbowBird <git@luoling.moe>
2026-09-12 17:43:10 +08:00
Garfield Lee e447b15b0d refactor(provider-inference): move provider tests closer to implementations (#2529)
# Refactor: Move Provider Tests to provider-inference

## Summary

Move azure-openai and openrouter-ai provider tests from `stage-ui` to
`provider-inference` package, placing them closer to their
implementations.

## Changes

- **Moved test files**:
-
`packages/stage-ui/src/libs/providers/providers/azure-openai/index.test.ts`
→
`packages/provider-inference/src/providers/cloud/azure-openai/index.test.ts`
-
`packages/stage-ui/src/libs/providers/providers/openrouter-ai/index.test.ts`
→
`packages/provider-inference/src/providers/cloud/openrouter-ai/index.test.ts`

- **Simplified test imports**: Updated tests to use direct provider
definitions instead of `getDefinedProvider()`, removing unnecessary
lookup logic

- **Added dependency**: `@proj-airi/core-agent` as devDependency for
test utilities

## Benefits

1. Tests are co-located with their implementations
2. Direct imports are simpler and more maintainable
3. Better package organization following module boundaries

## Verification

```bash
# Run tests for provider-inference
pnpm -F @proj-airi/provider-inference exec vitest run

# Typecheck
pnpm -F @proj-airi/provider-inference typecheck
```

## Test Results

All tests pass after the refactoring.
2026-09-12 10:25:16 +08:00
Garfield Lee cf6ff23f7c refactor(core-agent): move spark-command agent from stage-ui to core-agent (#2528)
## Summary

Move `spark-command` and `spark-notify` agents from
`packages/stage-ui/src/tools/character/orchestrator/` to
`packages/core-agent/src/agents/` for better separation of concerns and
reusability across packages.

## Changes

- **Relocate spark-command agent** — moved `spark-command-shared.ts`,
`spark-command.ts`, and `spark-command.test.ts` to
`packages/core-agent/src/agents/spark-command/`
- **Relocate spark-notify test** — moved `spark-notify.test.ts` to
`packages/core-agent/src/agents/spark-notify/`
- **Add barrel export** — created
`packages/core-agent/src/agents/spark-command/index.ts` with re-exports
- **Update package.json** — added `./agents/spark-command` entry in
`packages/core-agent/package.json`
- **Update build config** — added `src/agents/spark-command/index.ts` to
`tsdown.config.ts` entry list
- **Consolidate schemas** — merged duplicate
`sparkNotifyCommandGuidanceSchema` into `sparkCommandGuidanceSchema`
- **Add JSDoc** — added `@example` blocks to all normalize functions in
`schema.ts`
- **Update imports** — provider tests and `tool-resolver.ts` now import
from `@proj-airi/core-agent/agents/spark-command`
- **Delete legacy shims** — removed `stage-ui/src/tools/character/`
re-export layer

## Verification

```bash
pnpm -F @proj-airi/core-agent typecheck
pnpm -F @proj-airi/stage-ui typecheck
pnpm -F @proj-airi/core-agent exec vitest run
pnpm lint
```
2026-09-12 09:34:05 +08:00
Neko 3fcae726c5 fix(stage-layouts): center the mobile chat input (#2517) 2026-09-11 02:36:18 +08:00
Arata c30d169543 fix(stage-ui-live2d): preserve lip sync during MAGIC motion (#2481) 2026-09-11 01:56:54 +08:00
Neko 69ca0a9171 feat(stage-web): show FPS history in performance visualizer (#2516) 2026-09-11 01:46:40 +08:00
Weathercoldandgithub-actions[bot] 22b164bab0 chore(nix): update pnpmDeps hash (#2515)
Auto-generated by CI to keep Nix pnpmDeps hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-10 16:47:58 +00:00
bianyi ac3601c061 chore(CONTRIBUTING.md): align setup guides with pinned tooling (#2503) 2026-09-11 00:34:17 +08:00
Lovehsigure_520 8928dca0b5 fix(stage-tamagotchi): restore macOS Steam signing (#2509) 2026-09-11 00:33:07 +08:00
Neko 2904b795dd fix(stage-ui): keep mobile swipe attached to touch (#2514) 2026-09-10 21:42:17 +08:00
LuluandCursor 9a76eaec32 fix(server): trust moeru-ai Cloudflare Workers preview origins (#2513)
## Summary

- Auth and API origin policy now trusts `*.moeru-ai.workers.dev`.
- The retired `*.kwaa.workers.dev` suffix is removed. Server-dev
stage-web previews on the moeru-ai Cloudflare account can complete OIDC
login.

## Test plan

- [x] `pnpm exec vitest run server/apps/auth/src/tests/auth.test.ts
server/apps/auth/src/tests/origin.test.ts
server/apps/api/src/utils/tests/origin.test.ts`
- [ ] After deploy, sign in from
https://server-dev-moeru-ai-airi.moeru-ai.workers.dev and confirm
`/auth/callback` is accepted.

## Visual changes

No user-visible changes.


Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 20:28:17 +08:00
leafyy 3c9e60907c test(stage-tamagotchi): stabilize interactive area browser fixtures (#2510)
## Summary

The desktop browser suite can mount `InteractiveArea` before its utility
styles settle, then scroll history while the reply composer is still
expanding. A pending Virtua tail scroll can replace the message that the
test selected and make the scrollport assertion fail.

This addresses the pre-existing browser-test failure reported during
#2506 ([CI
failure](https://github.com/moeru-ai/airi/actions/runs/34448585692/job/102804067154)).

- Scan desktop and shared Vue components before the initial test
stylesheet is served. Load the desktop UnoCSS config explicitly so
config discovery does not replace the scan.
- Give each fixture a window-sized host, reset the viewport, and dispose
the component, host, and Pinia after each test.
- Wait for the reply transition and virtual-list measurements to settle
before scrolling. Cover both 200 ms and 1 s transitions, and assert the
requested scroll position throughout the existing message-mount checks.

Only browser tests and their configuration change.

## Validation

The complete desktop browser suite passed with three shuffled seeds: **6
files, 65 tests per run**, with no skipped tests.

```sh
for seed in 2508 2506 2507; do
  npm_config_registry=https://registry.npmjs.org/ NODE_OPTIONS=--no-experimental-webstorage \
    pnpm exec vitest run --config apps/stage-tamagotchi/vitest.config.ts \
    --project browser --sequence.shuffle --sequence.seed="$seed" --bail=1
done
npm_config_registry=https://registry.npmjs.org/ pnpm run typecheck
npm_config_registry=https://registry.npmjs.org/ pnpm run lint
git diff --check
```

Typecheck passed all 52 tasks. Lint passed with existing repository
warnings. ResizeObserver loop warnings remain visible; this change does
not suppress them. Linux CI validation is pending.
2026-09-10 17:41:29 +08:00
Neko 21d0e9d3a7 fix(stage-ui): use touch events for mobile swipe (#2508) 2026-09-10 16:11:09 +08:00
Weathercoldandgithub-actions[bot] 13ae708541 chore(nix): update assets hash (#2501)
Auto-generated by CI to keep Nix asset hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-10 15:01:52 +08:00
Neko b2a7dc252c fix(stage-ui): center mobile user message text (#2505) 2026-09-10 14:59:33 +08:00
Weathercoldandgithub-actions[bot] dfc6951a55 chore(nix): update pnpmDeps hash (#2500)
Auto-generated by CI to keep Nix pnpmDeps hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-09 16:31:37 +00:00
leafyy d7f38783f7 fix(stage-ui): persist speech provider settings (#2497) 2026-09-10 00:21:06 +08:00
Lovehsigure_520 352a9e389b fix(stage-ui): restore TTS after first login (#2490) 2026-09-10 00:08:35 +08:00
Younsang Na 41f9fb616b fix(computer-use-mcp): fix type errors at serivce/computer-use-mcp (#2494) 2026-09-10 00:06:02 +08:00
Younsang Na db2f8e3064 chore: optimize typecheck execution (#2499) 2026-09-10 00:03:27 +08:00
Neko 0d7b5e9a60 feat(stage-ui): add swipe to reply for chat messages (#2489) 2026-09-10 00:01:53 +08:00
Weathercoldandgithub-actions[bot] 3e94ea816c chore(nix): update pnpmDeps hash (#2496)
Auto-generated by CI to keep Nix pnpmDeps hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-09 18:51:34 +08:00
Weathercoldandgithub-actions[bot] 94873f8515 chore(nix): update assets hash (#2495)
Auto-generated by CI to keep Nix asset hash up-to-date.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-09 08:37:30 +00:00
RainbowBird 66f0d45028 refactor(analytics): replace PostHog with OpenPanel (#2480) 2026-09-09 08:26:18 +00:00