Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d99b66e
TTSをAzure SpeechからOpenAI gpt-4o-mini-ttsの女性声へ全面移行 (#2)
TinyKitten Aug 13, 2026
b2ea58b
TTSの既定ボイスを日英で分けて早口寄りに調整する (#3)
TinyKitten Aug 13, 2026
7782d5c
AIチャットのモデルにGemini(Vertex AI)を追加する (#4)
TinyKitten Aug 17, 2026
bf4776d
TTSをOpenAIからGoogle Cloud Text-to-Speechへ全面移行する (#5)
TinyKitten Aug 17, 2026
16a6518
本番の AGENT_MODEL を Gemini(Vertex AI)へ切り替える (#6)
TinyKitten Aug 17, 2026
335bbf4
staging の駅検索を sapi-bff-stg から stationapi-stg へ切り替える (#7)
TinyKitten Aug 22, 2026
d7dcbb3
本番の駅検索を sapi-bff から stationapi へ切り替える (#9)
TinyKitten Aug 23, 2026
7370018
フィードバックを原因リポジトリへ振り分け、トリアージの起票品質を改善する (#14)
TinyKitten Aug 27, 2026
f850f3e
アプリ指定の読み上げ速度を受け付け既定速度を等速へ変更 (#16)
TinyKitten Aug 27, 2026
06ce6bc
フィードバックのキューに dead letter queue を設定する (#19)
TinyKitten Aug 27, 2026
631398b
DLQ の紐付けを確認する手順を README に追加する (#22)
TinyKitten Aug 27, 2026
8c47ab7
フィードバック再試行での Issue 重複起票を防ぐ (#23)
TinyKitten Aug 28, 2026
94a409c
AI エージェントのモデルを Gemini 3.8 Flash へ更新する (#24)
TinyKitten Sep 3, 2026
f3fa862
英語TTSで「Keisei」が「かいせい」と読まれる誤読を合成前の表記置換で修正する (#25)
TinyKitten Sep 6, 2026
e73f616
GitHub Actions で dev・master からのデプロイを自動化する (#26)
TinyKitten Sep 6, 2026
a63ffe3
英語TTSで「Seibu」が「さいぶ」と読まれる誤読を合成前の表記置換で修正する (#27)
TinyKitten Sep 6, 2026
439ec90
master を dev へ取り込み AGENTS.md を同期する (#30)
TinyKitten Sep 12, 2026
3dda858
フィードバックトリアージの判定をTypeSafeに切り替える (#32)
TinyKitten Sep 17, 2026
6ee0bef
提案駅のリランクをTypeSafeで判定して対話ターンへ組み込む (#33)
TinyKitten Sep 17, 2026
cce388d
リランクの注記を user ロールで注入し Gemini でのターン失敗を直す (#34)
TinyKitten Sep 17, 2026
a81fe64
フィードバックから自動で修正PRを出すワークフローを追加 (#36)
TinyKitten Sep 21, 2026
fe49160
feedback-autofixを更新し準備が失敗した場合も結果を報告するようにした (#38)
TinyKitten Sep 21, 2026
0c1e8f3
本文が空白のみのフィードバックをpostFeedbackで弾くようにする (#39)
TinyKitten Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/actions/verify/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Verify worker
description: >-
lockfile どおりに依存を入れて lint / typecheck / test を回し、Worker が実際に
バンドルできることを dev・production 双方の設定で確認する。検証用ワークフローと
デプロイ用ワークフローで同じ手順を踏むため composite action に切り出してある。

inputs:
node-version:
description: Node.js のバージョン (package.json の engines と揃えること)
required: false
default: "22"

# ローカル action は checkout 済みでないと解決できないため、checkout は
# 呼び出し側のワークフローに置いてある。
runs:
using: composite
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
cache: npm

# npm install と違い package-lock.json を書き換えないので、ローカルで
# 動かしたのと同じ wrangler / biome / TypeScript の版で検証できる。
# wrangler もこの lockfile から入るため、デプロイに使う版の固定先は
# ワークフロー側ではなく package-lock.json 一箇所で済む。
- name: Install dependencies
shell: bash
run: npm ci

- name: Lint
shell: bash
run: npm run lint

- name: Typecheck
shell: bash
run: npm run typecheck

- name: Test
shell: bash
run: npm test

# tsc は型しか見ないので、import の解決ミスや nodejs_compat で賄えない
# Node API はバンドルして初めて落ちる。--dry-run は Cloudflare API を
# 叩かないため認証情報なしで回せる。
#
# dev と production を両方バンドルするのは、wrangler.jsonc の env.production
# 側だけが壊れている状態を master へ入れる前に捕まえるため。dev への push
# では production 設定に一切触れないまま緑になってしまう。
- name: Build (dry-run)
shell: bash
env:
WRANGLER_SEND_METRICS: "false"
# wrangler の色付けが Total Upload 行に混ざると要約が読めなくなる
NO_COLOR: "1"
run: |
# dev は wrangler.jsonc の top-level 設定。wrangler 4 は環境が複数ある
# 状態で --env を省くと警告を出すため、空文字でも明示する。
for target in "" production; do
label="${target:-dev}"
npx wrangler deploy --env="$target" --dry-run \
--outdir "$RUNNER_TEMP/bundle-$label" 2>&1 | tee "$RUNNER_TEMP/$label.log"
# Workers の上限は gzip 後で 10 MiB。今は 1/10 にも届かないので
# 失敗にはせず、増え方が見えるよう要約に残すだけにする。
size=$(grep -m1 'Total Upload' "$RUNNER_TEMP/$label.log" || true)
echo "- \`$label\`: ${size:-size unknown}" >> "$GITHUB_STEP_SUMMARY"
done
159 changes: 159 additions & 0 deletions .github/workflows/auto_fix_from_feedback.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# アプリに届いたフィードバックのうち、原因がこのリポジトリにあると判定された
# ものを Claude Code に読ませ、直せるなら修正の Pull Request まで作らせる。
#
# 起点はこのリポジトリのフィードバックトリアージが自分で立てるスタブ issue。
# 原因のリポジトリは受信時に判定済みなので、ここで振り分けをやり直さない。
# 判定・無害化・プロンプトの組み立て・結果の報告は TrainLCD/feedback-autofix
# の composite action が持っている。
#
# 出来上がった PR は必ず人がレビューすること。フィードバックの本文はアプリの
# 利用者がそのまま書いたもので、誰かが内容を確かめる工程が無い。個人情報を
# 取り除いたうえでデータとして渡しているが、プロンプトインジェクションの
# 抜け道を完全にはふさげない。自動マージもしない。
name: Auto Fix From Feedback

on:
# トリアージがこのリポジトリに立てるスタブ issue を起点にする。
issues:
types: [opened]
# 取りこぼしをやり直すときと、スタブを介さず動かすときに使う。
workflow_dispatch:
inputs:
issue_number:
description: "TrainLCD/Issues の issue 番号"
required: true
type: string

permissions:
contents: write
# prepare がスタブ issue を GITHUB_TOKEN で取得する。permissions を書いた
# 時点で挙げなかった権限は none になるので、これを省くとそこで止まる。
issues: read
pull-requests: write

# 同じ管理チケットに対する実行を直列にする。スタブ issue の番号で束ねると、
# 同じチケットを指すスタブが 2 つあったときに別のグループへ入って同時に走る。
# エージェントが 2 つ動き、同じ名前のブランチを取り合う。
#
# 題名には管理チケットへの参照が入っていて、トリアージが立てるものも引き継ぎで
# 立つものも同じ形なので、これで同じチケットは同じグループに入る。
# cancel-in-progress を false にしてあるので後続は待たされ、先行が結果を
# 書き終えてから動き出してそこで打ち切られる。
#
# 題名にコロンが入るため、値は引用符で囲むこと。囲まないと YAML がそこを
# キーの区切りと読み、このファイルを読み込めなくなる。
concurrency:
group: "auto-fix-from-feedback-${{ github.event.issue.title || format('フィードバック対応: {0}#{1}', 'TrainLCD/Issues', inputs.issue_number) }}"
cancel-in-progress: false

jobs:
auto-fix:
name: Auto fix from feedback
runs-on: ubuntu-latest
timeout-minutes: 60

# environment を宣言しない。ci.yml と同じ理由で、宣言するとこのジョブが
# その環境へのデプロイとして履歴に載り、環境 Secret に触れる状態になる。
steps:
# persist-credentials: false を外さないこと。既定の true だと、書き込み
# 権限付きの GITHUB_TOKEN がローカルの git 設定に残り、npm ci の
# postinstall とエージェントの Bash(git:*) から素で使える状態になる。
# 外部 action は可変タグではなく commit SHA で固定する。このジョブは
# contents: write と pull-requests: write を持ち、secret も渡している。
# タグが差し替えられると、その内容がここで動く。
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
ref: ${{ github.event.repository.default_branch }}
fetch-depth: 0
persist-credentials: false

- uses: TrainLCD/feedback-autofix/prepare@c71e2b4abf4149b4b83e9a87cd185b1558ed8237 # feedback-autofix#4
id: prepare
with:
stub_issue_number: ${{ github.event.issue.number }}
issue_number: ${{ inputs.issue_number }}
# スタブ issue の作成者として認めるアカウントの数値 ID。このリポジトリ
# は公開されていて issue は誰でも立てられるので、これが無いと第三者が
# 管理チケットの番号を書いた issue を立てるだけで、非公開チケットの
# 本文を取得させられる。
allowed_authors: "32848922"
issues_repo_token: ${{ secrets.ISSUES_REPO_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# 共通アクションの既定は P1 だけ。2026 年に入って立った Bug は P1 が
# 8 件、P2 が 43 件、P3 が 3 件(duplicate と Spam を除く)で、P1 だけだと
# 月 1 件動くかどうかになる。3 つ足しても月 6 件程度(54 件 ÷ 8.6 か月)。
#
# P3 を外す理由は無い。作るものから決める Feature Request や Improvement は
# カテゴリの条件が弾くので、ここへ残るのは Bug と Crash だけ。
#
# 3 つとも入れたことでこの条件はほぼ素通りになるが、外さないこと。優先度が
# 付く前の issue を先に渡さないための関門になっている。
triage_labels: "🟠 P1 / High,🟡 P2 / Medium,🟢 P3 / Low"
handoffs: MobileApp,StationAPI
guidelines_file: AGENTS.md
# このリポジトリに PR テンプレートは無い。
pr_template: ""
# .github/actions/verify/action.yml が回すものと同じ。バンドルまで
# 入れてあるのは、tsc が型しか見ないため、import の解決ミスや
# nodejs_compat で賄えない Node API はバンドルして初めて落ちるから。
# これを省くと、3 つを通した PR が CI のビルドで落ちる。
checks: |
npm run lint
npm run typecheck
npm test
npx wrangler deploy --env="" --dry-run --outdir /tmp/feedback-autofix-bundle-dev
npx wrangler deploy --env=production --dry-run --outdir /tmp/feedback-autofix-bundle-production
scope: |
- `src/**` の Worker のコード
- `test/**` のテスト

# ここから先は対象だったときだけ走らせる。届く issue のうち条件を満たす
# ものは一部なので、判定より先に重い準備を置かない。
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
if: steps.prepare.outputs.eligible == 'true'
with:
# package.json の engines と .github/actions/verify の既定に揃えること。
node-version: "22"
cache: npm

- run: npm ci
if: steps.prepare.outputs.eligible == 'true'

- uses: anthropics/claude-code-action@cfc3eb22bfed5c26ef66e3223c982af27e4524de # v1
id: claude
if: steps.prepare.outputs.eligible == 'true'
env:
# wrangler の色付けが Total Upload 行に混ざると読めなくなる。
NO_COLOR: "1"
WRANGLER_SEND_METRICS: "false"
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
prompt: ${{ steps.prepare.outputs.prompt }}
claude_args: |
# Sonnet で始める。まず費用を見たいため。上げるかどうかは「直せない」と
# 誤って判断した件数で決めること。この経路がいちばん高くつく。管理チケット
# に「済み」の目印が残り、次から打ち切られるので、手つかずのまま対応済みに
# 見える。出来の悪い修正は人のレビューで止まるが、誤った辞退は止まらない。
--model claude-sonnet-5
--allowedTools "Edit,Read,Write,Glob,Grep,TodoWrite,Bash(npm:*),Bash(npx:*),Bash(git:*),Bash(gh:*),Bash(node:*)"

# always() を外さないこと。エージェントが失敗した場合こそ報告が要る。
# 何も言わずに終わると、管理チケットを見た人には「調べたうえで何もしな
# かった」のか「そもそも動かなかった」のかが分からない。
#
# failed も外さないこと。prepare が対象だと分かったあとで落ちた場合、
# eligible は 'true' になりません。この条件が無いとここが走らず、ジョブが
# 赤くなるだけで管理チケットには何も残りません。
- uses: TrainLCD/feedback-autofix/report@c71e2b4abf4149b4b83e9a87cd185b1558ed8237 # feedback-autofix#4
if: ${{ always() && (steps.prepare.outputs.eligible == 'true' || steps.prepare.outputs.failed == 'true') }}
with:
issue_number: ${{ steps.prepare.outputs.issue_number }}
issues_repo_token: ${{ secrets.ISSUES_REPO_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ steps.prepare.outputs.branch }}
verdict_path: ${{ steps.prepare.outputs.verdict_path }}
claude_outcome: ${{ steps.claude.outcome }}
# 引き継ぎ先に issue を立てられるトークン。省くと引き継ぎ先の名前が
# コメントに出るだけで、向こうは動かない。
handoff_token: ${{ secrets.HANDOFF_ISSUE_TOKEN }}
85 changes: 85 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# lint / typecheck / test が通ることと、Worker がバンドルできることを検証する
# だけのワークフロー。デプロイはしない。
#
# デプロイは環境ごとに別ファイルへ分けてある:
# dev -> deploy_dev.yml (trainlcd-worker-dev)
# master -> deploy_production.yml (trainlcd-worker)
# デプロイ先をトリガとファイルで固定することで、他のブランチが誤って
# どこかの環境へ向くことがないようにしている。
on:
pull_request:
# GitHub Actions は YAML のアンカー / エイリアスを解釈しないため、
# このリストは push 側とも、デプロイ用の 2 ファイルとも二重に書く必要が
# ある。片方だけ直さないこと。
paths:
- "src/**"
- "test/**"
- "scripts/**"
- "package.json"
- "package-lock.json"
- "tsconfig.json"
- "biome.json"
- "jest.config.js"
- "wrangler.jsonc"
- ".github/actions/verify/action.yml"
- ".github/workflows/ci.yml"
# deploy 用の 2 ファイルはどちらも pull_request で起動しないため、
# ここに載せておかないと変更した PR がどの workflow も通らないまま
# マージされ、デプロイ時に初めて動くことになる。
- ".github/workflows/deploy_dev.yml"
- ".github/workflows/deploy_production.yml"
push:
# dev / master は deploy_dev.yml / deploy_production.yml が同じ composite
# action で検証してからデプロイするため、ここでは走らせない。
branches-ignore:
- dev
- master
paths:
- "src/**"
- "test/**"
- "scripts/**"
- "package.json"
- "package-lock.json"
- "tsconfig.json"
- "biome.json"
- "jest.config.js"
- "wrangler.jsonc"
- ".github/actions/verify/action.yml"
- ".github/workflows/ci.yml"
# deploy 用の 2 ファイルはどちらも pull_request で起動しないため、
# ここに載せておかないと変更した PR がどの workflow も通らないまま
# マージされ、デプロイ時に初めて動くことになる。
- ".github/workflows/deploy_dev.yml"
- ".github/workflows/deploy_production.yml"
workflow_dispatch:

name: Continuous integration

# 同じ PR / ブランチに続けて push したとき、古い方は結果が要らない。
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
verify:
name: Lint, typecheck, test and build
runs-on: ubuntu-latest

# ここでは environment を宣言しない。environment は if: と違って
# ジョブが走れば必ず適用されるため、宣言すると全ブランチ・全 PR が
# その環境へのデプロイとして履歴に載り、環境 Secret (デプロイ用の
# CLOUDFLARE_API_TOKEN を含む) が任意のブランチのビルドから触れる。
#
# 検証は --dry-run で Cloudflare API を叩かないため、そもそも認証情報が要らない。
steps:
# checkout は既定で GITHUB_TOKEN を .git/config に残す。後続の npm ci は
# 依存パッケージの install スクリプトを実行するため読み取られうる。
# ここから先で git 認証は使わない。
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: ./.github/actions/verify
69 changes: 69 additions & 0 deletions .github/workflows/deploy_dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# dev を dev 環境 (trainlcd-worker-dev) へデプロイする。
#
# デプロイ先はこのファイルとトリガで固定してある。ブランチを式で判定して
# 環境を選ぶ作りにすると、environment は if: と違ってジョブが走れば必ず
# 適用されるため、意図しないブランチがこの環境の履歴と Secret に触れる。
on:
push:
branches:
- dev
# GitHub Actions は YAML のアンカー / エイリアスを解釈しないため、
# このリストは ci.yml / deploy_production.yml とも二重に書く必要がある。
# 片方だけ直さないこと。
paths:
- "src/**"
- "test/**"
- "scripts/**"
- "package.json"
- "package-lock.json"
- "tsconfig.json"
- "biome.json"
- "jest.config.js"
- "wrangler.jsonc"
- ".github/actions/verify/action.yml"
- ".github/workflows/deploy_dev.yml"
workflow_dispatch:

name: Deploy to dev

# 同時に流れると、先に始まった古い版が後から上書きしうる。
concurrency:
group: deploy-dev
cancel-in-progress: false

permissions:
contents: read

jobs:
deploy:
name: Verify and deploy to dev
runs-on: ubuntu-latest

# workflow_dispatch にはブランチ絞り込みが無いので、ここで塞ぐ。
# push は on: branches で dev に限定済み。
if: github.ref == 'refs/heads/dev'

environment: dev

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- uses: ./.github/actions/verify

# 直前の検証で --dry-run 済みのものと同じ入力から同じバンドルが組み上がる。
# wrangler は node_modules から解決されるので、検証と同じ版が走る。
#
# dev は wrangler.jsonc の top-level 設定なので環境名は空にする。
# wrangler 4 は環境が複数あると --env の省略を警告するため、空でも明示する。
#
# Worker の secrets (SESSION_JWT_SECRET など) はここでは触らない。
# deploy は既存の secrets を保持するため、投入は scripts/put-secrets.sh で
# 手元から行う運用のままでよい。
- name: Deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
WRANGLER_SEND_METRICS: "false"
run: npx wrangler deploy --env=""
Loading
Loading