diff --git a/Makefile b/Makefile index 37aa835..7ab13b6 100644 --- a/Makefile +++ b/Makefile @@ -16,3 +16,7 @@ up: down: @bash scripts/down.sh + +restart: + @bash scripts/down.sh + @bash scripts/up.sh diff --git a/bun.lock b/bun.lock index 47a60c3..ea384a5 100644 --- a/bun.lock +++ b/bun.lock @@ -16,6 +16,7 @@ "pino": "^10.3.1", "pino-pretty": "^13.1.3", "uuid": "^13.0.0", + "yaml": "^2.8.3", }, "devDependencies": { "@eslint/js": "^10.0.0", @@ -760,7 +761,7 @@ "y18n": ["y18n@5.0.8", "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yaml": ["yaml@2.8.2", "https://registry.npmmirror.com/yaml/-/yaml-2.8.2.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], + "yaml": ["yaml@2.8.3", "https://bnpm.byted.org/yaml/-/yaml-2.8.3.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], "yargs": ["yargs@17.7.2", "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], @@ -796,6 +797,8 @@ "fdir/picomatch": ["picomatch@4.0.3", "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "lint-staged/yaml": ["yaml@2.8.2", "https://registry.npmmirror.com/yaml/-/yaml-2.8.2.tgz", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], + "log-update/slice-ansi": ["slice-ansi@7.1.2", "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-7.1.2.tgz", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], "send/mime-types": ["mime-types@3.0.2", "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], diff --git a/docs/designs/group-workspace-binding.md b/docs/designs/group-workspace-binding.md new file mode 100644 index 0000000..b163f27 --- /dev/null +++ b/docs/designs/group-workspace-binding.md @@ -0,0 +1,210 @@ +# Group Workspace Binding Design + +Enable one agentara bot to serve multiple Feishu groups. Each group binds to its own workspace (a multi-repo directory) with an active `(repo, branch)` pointer. Every Feishu topic inside a group becomes an isolated session that follows the group's live binding. + +## Goals + +- One bot process, N Feishu groups — registered dynamically at runtime +- Per-group workspace directory (can host multiple cloned repos, all visible to the agent in one session) +- Per-topic session within a group (flexible + isolated) +- Gateway-level slash commands that bypass the LLM +- Default workspace fallback when a group is not bound +- `dev-assets` memory works across all repos in the workspace (requires the suite-side workspace mode — see `branch-context-skill-suite/docs/workspace-mode.md`) + +## Non-Goals + +- Per-topic workspace override (binding lives at group level only) +- Multiple simultaneously-active repos inside one workspace +- Rich card UI for `/setup` in v1 (text commands first, card in v2) + +## Data Model + +### `group_workspaces` (new table) + +| Field | Type | Notes | +|-------|------|-------| +| `chat_id` | text, PK | Feishu `chat_id` | +| `workspace_path` | text | Absolute path, always `$AGENTARA_HOME/workspaces//` | +| `active_repo` | text, nullable | Directory name under `workspace_path` | +| `active_branch` | text, nullable | Git branch name | +| `created_at` | int | epoch ms | +| `updated_at` | int | epoch ms | + +Row absence = group is unbound. `active_repo = null` while `workspace_path` exists = workspace reserved but no repo selected yet. + +### `sessions` (schema extension) + +Add two fields to the existing `Session` schema (`src/shared/sessioning/types/session.ts`): + +- `chat_id: string | null` — owning Feishu group +- `thread_id: string | null` — Feishu topic root message id + +Keep `cwd` for backward compatibility, but **it is now a hint, not a source of truth**. Actual cwd is resolved dynamically on every dispatch (see Resolution Flow). + +### Default workspace + +Path: `$AGENTARA_HOME/workspaces/_default/` + +Created by boot-loader on first run. Used when a message arrives from an unbound group or from a group whose binding has `active_repo = null`. + +## Feishu Channel Rework + +### Current (`src/kernel/kernel.ts:87-99`) + +`config.yaml` lists each Feishu channel; one `FeishuMessageChannel` instance per chat, constructor-bound to a specific `chat_id`. Adding a group = editing config + restart. + +### New + +- Exactly one `FeishuMessageChannel` instance, **no `chat_id` filter** +- Subscribes to all group events the bot is a member of (Feishu WS IM event stream already broadcasts to the bot user; filter only on event type, not chat) +- Inbound event carries `chat_id` + `root_id` (topic id when the message is inside a topic; equals message id otherwise) +- `UserMessage.channel_id` remains the agentara internal channel id (single value for the one Feishu channel); the Feishu `chat_id` and `root_id` are carried as new fields on `UserMessage` + +### Session id derivation + +``` +session_id = `feishu:${chat_id}:${thread_id}` +``` + +- First message inside a topic → `resolveSession` creates +- Subsequent messages in same topic → `resolveSession` resumes +- Messages outside any topic (direct `@mention` with no threading) → treated as topic whose `thread_id = message_id` (each becomes its own fresh session; encourages the bot to always reply in a topic so follow-ups resume correctly) + +## Gateway Commands + +Parsed in `Kernel._handleInboundMessage` (`src/kernel/kernel.ts:114`) before `TaskDispatcher.dispatch()`. Prefix: `/` (matches Claude Code convention). Commands execute synchronously, reply via `_messageGateway.replyMessage`, do not dispatch an LLM task. + +| Command | Scope | Effect | +|---------|-------|--------| +| `/setup` | group | Reply with an interactive card. User picks repo + branch; card submit writes group binding. v1 may fall back to `/bind`. | +| `/bind ` | group | Upsert `group_workspaces` row, set `active_repo` + `active_branch`. Rejects if `` not in workspace (suggests `/clone`). | +| `/unbind` | group | Delete `group_workspaces` row. | +| `/status` | group + topic | Show group binding, list cloned repos, show current topic's `session_id`. | +| `/clone [name]` | group | `git clone` into `workspace_path`. Rejects on name collision. | +| `/checkout ` | group | `git checkout` in active repo; updates `active_branch`. Rejects on dirty tree. | +| `/ls` | group | List directories under `workspace_path`. | +| `/new` | topic | Archive current session for this topic; next message opens a new session with the same `session_id` reset (or appends a generation suffix). | +| `/agent ` | topic | Overrides `agent_type` for the current session only; re-resolve session with new runner type. | + +Already-implemented reference: `/stop` (`src/kernel/kernel.ts:118`). Extend the same if-chain into a command table. + +Card interaction for `/setup` should mirror the streaming card pattern in `remote_claude/lark_client/shared_memory_poller.py` + interactive element handling in Feishu card-action callbacks. Deferred to v2. + +## Resolution Flow + +Per inbound Feishu message: + +1. `FeishuMessageChannel` emits `message:inbound` with `{ chat_id, thread_id, text, ... }` +2. `Kernel._handleInboundMessage`: + - If text starts with `/` → dispatch to gateway command handler, reply, return + - Else compute `session_id` from `(chat_id, thread_id)` + - `TaskDispatcher.dispatch(session_id, { type: "inbound_message", message })` +3. `Kernel._handleInboundMessageTask`: + - Load `group_workspaces` row for `chat_id` + - Resolve cwd: + - No row → `cwd = $AGENTARA_HOME/workspaces/_default/` + - Otherwise → `cwd = workspace_path` (the workspace root, multi-repo container — **not** a single repo dir) + - If `active_repo` set: pre-checkout `git -C / checkout ` (idempotent) + - Build runner env extras: + - If `active_repo` set: `DEV_ASSETS_PRIMARY_REPO=`, `DEV_ASSETS_PRIMARY_BRANCH=` + - Else: omit (skill suite enters workspace mode without primary hint) + - `SessionManager.resolveSession(session_id, { cwd, chatId, threadId, envExtras, firstMessage })` + - `session.stream(message)` as today + +The cwd passed to `resolveSession` on resume overrides the stored `cwd` (supported today at `src/kernel/sessioning/session-manager.ts:174`). This is the mechanism for "live binding": each dispatch re-resolves. `envExtras` is a new option threaded through to the runner's `Bun.spawn` call so per-group env vars reach the underlying CLI. + +## dev-assets Integration + +The cwd contract changed: cwd is the group's workspace root (`workspaces//`), which is **not** a git repo but contains N cloned repos as first-level subdirectories. The native `dev-assets` skills assume cwd is inside a single git repo, so the suite needs an additive **workspace mode**. Suite-side design lives in `branch-context-skill-suite/docs/workspace-mode.md`. Summary: + +- `lib/dev_asset_common.py` gains `detect_workspace_mode()` + `list_repos_in_workspace()` (purely additive) +- Hook scripts (`session_start.py`, `stop.py`, `pre_compact.py`, `session_end.py`) take a workspace branch: when cwd has no `.git` but first-level subdirs do, iterate all repos +- Single-repo cwd behavior is unchanged; existing installations see no difference + +### agentara-side contract + +When dispatching, agentara passes to the runner: + +- `cwd = workspaces//` (workspace root) +- env `DEV_ASSETS_PRIMARY_REPO=` (basename) — focus repo from group binding +- env `DEV_ASSETS_PRIMARY_BRANCH=` — informational + +The skill suite then: + +- **SessionStart**: full memory for primary repo + brief overview-only summary for other repos in workspace +- **Stop / SessionEnd**: record HEAD for all repos in workspace (cheap, idempotent) +- **dev-assets-sync** (LLM-invoked): defaults to primary when no `--repo` flag; LLM can pass `--repo=` to write to another repo +- **dev-assets-context** (LLM-invoked): can target a non-primary repo via `--repo=` to load its full memory mid-session + +Codex parity: SessionStart + Stop hooks fire identically. Codex lacks PreCompact/SessionEnd, but those don't affect multi-repo correctness — only Claude-only checkpoint refinement. + +### Default workspace + +For `_default` (no binding): no `DEV_ASSETS_PRIMARY_REPO` set. Suite enters workspace mode and lists whatever repos the user happens to have cloned in there. Empty `_default` → suite no-ops (acceptable). + +### Cross-group memory sharing + +Memory is keyed by `(repo_identity, branch)` derived from git remote URL (or local path fallback). Two groups bound to the same `(repo, branch)` automatically share memory under `~/.dev-assets/repos//branches//` — no agentara code involved. + +## Concurrency & Ordering + +- Same `(chat_id, thread_id)` → same `session_id` → serial execution via `TaskDispatcher`'s per-session queue (existing guarantee). +- Different topics in same group → different `session_id` → parallel execution (existing guarantee). +- `/checkout` interleaved with an in-flight LLM turn in another topic of the same group: the running runner's `cwd` (workspace root) is unchanged, but the active repo's HEAD shifts under it. Tool calls touching `//**` may see the new branch's files mid-turn. Acceptable per Q6(b) — live binding is the user's explicit choice. Other repos in the workspace are unaffected. +- Two simultaneous `/checkout` on same group: serialize via a per-chat mutex in the gateway command layer (reuse `TaskDispatcher` isn't right — commands are synchronous). Simple `Map` mutex. + +## Error Handling + +Strict; no silent coercion. + +- `/bind ` where `` directory absent → reply with suggestion to run `/clone`. +- `/clone` with name collision → reject. +- `/checkout` on dirty tree → reply with `git status --short` output; require user to resolve manually. +- `/unbind` when no row → reply "group is not bound". +- Inbound message from group with no binding → silently fall back to `_default`, no error. +- Feishu event missing `chat_id` → log error, drop event. +- Gateway command execution failure → reply with error text; do not dispatch LLM fallback. + +## Config Changes + +`config.yaml`: + +- `messaging.channels` entries for Feishu no longer need `chat_id` (ignored if present, logged as deprecation) +- Add optional `messaging.default_workspace_path` to override `$AGENTARA_HOME/workspaces/_default/` + +No breaking change for users with existing single-chat config — a missing `chat_id` is now valid and means "listen to all groups". + +## Files Touched + +| File | Change | +|------|--------| +| `src/shared/sessioning/types/session.ts` | Add `chat_id`, `thread_id` fields | +| `src/kernel/sessioning/data.ts` | Drizzle schema: add columns + new `group_workspaces` table | +| `src/kernel/sessioning/session-manager.ts` | Pass through new fields on create/resume | +| `src/kernel/workspaces/` (new dir) | `GroupWorkspaceStore` (CRUD over `group_workspaces`), cwd resolver | +| `src/kernel/commands/` (new dir) | Slash command parser + handlers | +| `src/community/feishu/messaging/` | Remove per-chat filter; forward `chat_id` + `root_id` on inbound | +| `src/kernel/kernel.ts` | Wire command parser into `_handleInboundMessage`; wire cwd resolver + env extras into `_handleInboundMessageTask` | +| `src/shared/agents/agent-runner.ts` | Add `envExtras?: Record` to `AgentRunOptions` schema | +| `src/community/anthropic/claude-agent-runner.ts` | Merge `envExtras` into `Bun.spawn` env (preserve `ANTHROPIC_API_KEY: ""` clear for subscription auth) | +| `src/community/openai/codex-agent-runner.ts` | Merge `envExtras` into `Bun.spawn` env | +| `src/shared/messaging/types/message.ts` | Extend `UserMessage` with `chat_id`, `thread_id` optional fields | +| `src/boot-loader/boot-loader.ts` | Ensure `workspaces/_default/` exists on first run | +| `docs/overview.md` | Append "Group Workspace Binding" section linking here | + +## Implementation Order + +1. Schema additions (`group_workspaces` table, `Session` fields, `UserMessage` fields) + migration +2. `GroupWorkspaceStore` CRUD + cwd resolver +3. Feishu channel multi-group refactor (forward `chat_id` + `root_id`) +4. Session id derivation in kernel from `(chat_id, thread_id)` +5. Dynamic cwd resolution at dispatch +6. Slash command parser + core handlers (`/bind`, `/unbind`, `/status`, `/clone`, `/checkout`, `/ls`) +7. `/new`, `/agent` — session lifecycle commands +8. Default workspace bootstrap +9. v2: `/setup` Feishu card interaction + +## Open Questions + +- Feishu `root_id` behavior when the bot itself opens a topic vs when user does: verify the id is stable across the whole thread. (Implementation detail; does not change design.) +- `/new` semantics: does archiving mean deleting the JSONL or renaming? Propose rename to `.archived-.jsonl` so the DB row is kept for audit. Decide during implementation. diff --git a/docs/designs/setup-flow.md b/docs/designs/setup-flow.md new file mode 100644 index 0000000..9b79023 --- /dev/null +++ b/docs/designs/setup-flow.md @@ -0,0 +1,127 @@ +# SetupFlow Design + +Interactive `/setup` command: presents a Feishu card with pre-defined repositories (sourced from `$AGENTARA_HOME/REPOS.md`), collects user's repo+branch selections via a form submit, then clones, checks out, and binds the group workspace in one shot. + +Specialized, **not** generic — no broader "interactive card framework". Only `/setup` triggers this path. Day-to-day binding uses `/bind `. + +## Dependencies + +- `src/shared/config/predefined-repos.ts` — `PredefinedRepo` Zod schema + `loadPredefinedRepos()` Markdown parser +- `src/community/feishu/messaging/types/interactive/` — element types (form, checker, input, button, column_set, select_static) +- `src/community/feishu/messaging/message-channel.ts` — subscribes `card.action.trigger`, emits `card:action`, exposes `sendRawCard` and `updateRawCard` +- `src/shared/messaging/message-channel.ts` + `message-gateway.ts` — `"card:action"` event type +- `src/kernel/workspaces/store.ts` — reuses `upsertBinding`, `resolve` +- `src/kernel/kernel.ts` — special-cases `/setup` like `/stop`; subscribes `card:action` +- `src/boot-loader/boot-loader.ts` — seeds an empty `REPOS.md` on first boot and ensures CLAUDE.md references it + +## Source — `$AGENTARA_HOME/REPOS.md` + +The repo catalog lives in a Markdown file instead of `config.yaml` so the +same file can double as agent-readable context. CLAUDE.md imports it via +Claude Code's native `@REPOS.md` syntax; the boot-loader appends that +reference automatically if missing. + +Each `## ` section defines one repo. The first `- git_url: ` +bullet supplies the clone URL; the first non-bullet prose line becomes +the one-line description rendered on the card. The rest of the section +body is free-form prose for the agent — and the agent is expected to +update those descriptions over time as it learns more about each repo. + +```markdown +## agentara + +- git_url: https://github.com/magiccube/agentara.git + +Bun + TypeScript personal assistant. Useful when a group is discussing +the kernel, session/task orchestration, or Feishu bot integration. +``` + +When `REPOS.md` is missing or yields zero parseable entries, `/setup` +replies with an error pointing the operator at the file. + +`loadPredefinedRepos()` is called on every `/setup` invocation — no +caching — so edits to the Markdown take effect immediately. + +## Card Shape + +Single Feishu Card 2.0 form with one row per predefined repo. Each row is a `column_set` with: +- `checker` — `name: repo_`, label is `` (plus `— ` when present) +- `input` — `name: branch_`, `placeholder: master`, no default value (empty submission means master) + +Below the rows: a `select_static` for primary-repo selection (`name: primary_repo`, options built from the catalog), always shown. + +Footer: `button` with `name: "setup_submit"` and `action_type: form_submit`. + +## Events + +`FeishuMessageChannel` handles `card.action.trigger` and normalizes the SDK payload into a minimal shape: + +```ts +interface CardActionPayload { + message_id: string; + action_name: string; // button/element name (e.g. "setup_submit") + operator_open_id: string; // who clicked + form_value: Record;// input/checker values on form_submit + chat_id: string; +} +``` + +Emitted as `card:action` on the channel; `MultiChannelMessageGateway` re-emits; kernel dispatches by `action_name` (only `"setup_submit"` recognized). + +## API + +### `SetupFlow` (`src/kernel/setup/setup-flow.ts`) + +```ts +class SetupFlow { + constructor(deps: { + workspaceStore: GroupWorkspaceStore; + feishuChannels: Map; // by channel_id + }); + + // Entry: called from kernel._handleInboundMessage when text === "/setup" + start(message: UserMessage): Promise; + + // Entry: called from kernel card:action listener when action_name === "setup_submit" + handleSubmit(payload: CardActionPayload): Promise; +} +``` + +### Pending state + +In-memory `Map` on the `SetupFlow` instance: + +```ts +interface PendingSetup { + chat_id: string; + initiator_open_id: string; + catalog_snapshot: PredefinedRepo[]; // frozen at card render time + created_at: number; +} +``` + +Lost on kernel restart — acceptable. On submit for an unknown `message_id`, the card is updated in place with an "expired, please re-run /setup" message. + +## Error Handling + +- `/setup` when `REPOS.md` is missing or empty → text reply: ask operator to fill in `REPOS.md`. +- `/setup` when the group is already bound (`upsertBinding` already present) → text reply: `已绑定 @,请先 /unbind`. +- `/setup` outside Feishu (`!message.chat_id`) → text reply: `/setup 仅在飞书群内可用`. +- Submit by non-initiator → update card: `这不是你的表单`. +- No repos selected on submit → update card: `未选择任何仓库`. +- Per-repo clone failure → keep successful clones, record the failed entry; show per-repo status in result card. +- Per-repo checkout failure → keep the clone, bind to whatever the clone landed on; warn on the card. +- All throws from the submit path → update card with `❌ 初始化失败: `. + +No silent fallback. No graceful retry. Every failure surfaces on the card. + +## Concurrency / Constraints + +- Single-writer to pending state: all access through one `SetupFlow` instance on the kernel. +- One pending setup per `chat_id` — a second `/setup` while another is pending replaces the first card's pending entry (in-memory map is keyed by `message_id`, so the earlier card becomes unreachable and effectively expired). +- Clone operations run sequentially within one submit, keeping output deterministic and avoiding concurrent writes to the same workspace directory. +- Primary-repo select always offers the full catalog (not just checked rows). If the primary isn't among the checked rows on submit, the handler falls back to the first checked row instead of rejecting. + +## Result Card + +After submit completes (success or partial), the original card is replaced with a result card (via `updateRawCard`) showing per-repo status (`✅ cloned` / `⚠️ checkout failed` / `❌ clone failed`), the final binding, and next-step hints. diff --git a/drizzle/0011_lean_enchantress.sql b/drizzle/0011_lean_enchantress.sql new file mode 100644 index 0000000..a422cf1 --- /dev/null +++ b/drizzle/0011_lean_enchantress.sql @@ -0,0 +1,11 @@ +CREATE TABLE `group_workspaces` ( + `chat_id` text PRIMARY KEY NOT NULL, + `workspace_path` text NOT NULL, + `active_repo` text, + `active_branch` text, + `created_at` integer NOT NULL, + `updated_at` integer NOT NULL +); +--> statement-breakpoint +ALTER TABLE `sessions` ADD `chat_id` text;--> statement-breakpoint +ALTER TABLE `sessions` ADD `thread_id` text; \ No newline at end of file diff --git a/drizzle/0012_workspace_ids.sql b/drizzle/0012_workspace_ids.sql new file mode 100644 index 0000000..2272e93 --- /dev/null +++ b/drizzle/0012_workspace_ids.sql @@ -0,0 +1,65 @@ +CREATE TABLE `workspaces` ( + `id` text PRIMARY KEY NOT NULL, + `name` text NOT NULL, + `path` text NOT NULL, + `created_at` integer NOT NULL, + `updated_at` integer NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `workspaces_path_unique` ON `workspaces` (`path`); +--> statement-breakpoint +WITH RECURSIVE `workspace_name_parts`(`chat_id`, `path`, `tail`) AS ( + SELECT + `chat_id`, + rtrim(`workspace_path`, '/'), + rtrim(`workspace_path`, '/') + FROM `group_workspaces` + UNION ALL + SELECT + `chat_id`, + `path`, + substr(`tail`, instr(`tail`, '/') + 1) + FROM `workspace_name_parts` + WHERE instr(`tail`, '/') > 0 +) +INSERT OR IGNORE INTO `workspaces` (`id`, `name`, `path`, `created_at`, `updated_at`) +SELECT + 'ws_' || lower(hex(randomblob(6))), + COALESCE(NULLIF(`parts`.`tail`, ''), '_workspace'), + `parts`.`path`, + `gw`.`created_at`, + `gw`.`updated_at` +FROM `workspace_name_parts` AS `parts` +JOIN `group_workspaces` AS `gw` ON `gw`.`chat_id` = `parts`.`chat_id` +WHERE instr(`parts`.`tail`, '/') = 0; +--> statement-breakpoint +ALTER TABLE `group_workspaces` RENAME TO `group_workspaces__old`; +--> statement-breakpoint +CREATE TABLE `group_workspaces` ( + `chat_id` text PRIMARY KEY NOT NULL, + `workspace_id` text NOT NULL, + `active_repo` text, + `active_branch` text, + `created_at` integer NOT NULL, + `updated_at` integer NOT NULL +); +--> statement-breakpoint +INSERT INTO `group_workspaces` ( + `chat_id`, + `workspace_id`, + `active_repo`, + `active_branch`, + `created_at`, + `updated_at` +) +SELECT + `old`.`chat_id`, + `ws`.`id`, + `old`.`active_repo`, + `old`.`active_branch`, + `old`.`created_at`, + `old`.`updated_at` +FROM `group_workspaces__old` AS `old` +JOIN `workspaces` AS `ws` ON `ws`.`path` = `old`.`workspace_path`; +--> statement-breakpoint +DROP TABLE `group_workspaces__old`; diff --git a/drizzle/0013_workspace_active_state.sql b/drizzle/0013_workspace_active_state.sql new file mode 100644 index 0000000..e61ad0f --- /dev/null +++ b/drizzle/0013_workspace_active_state.sql @@ -0,0 +1,33 @@ +-- Move active_repo/active_branch from `group_workspaces` up to `workspaces`. +-- Only one `.git/HEAD` exists per cloned repo, so the "active" state is a +-- workspace-on-disk property, not a per-binding property. Multiple groups +-- sharing a workspace should see the same active state. +ALTER TABLE `workspaces` ADD `active_repo` text;--> statement-breakpoint +ALTER TABLE `workspaces` ADD `active_branch` text;--> statement-breakpoint +-- Backfill: for each workspace, copy the active state from any existing +-- binding. Pre-migration each workspace maps 1:1 to a chat, so any binding +-- row is authoritative; if a shared workspace somehow exists, prefer the +-- most recently updated binding. +UPDATE `workspaces` +SET + `active_repo` = ( + SELECT `gw`.`active_repo` + FROM `group_workspaces` AS `gw` + WHERE `gw`.`workspace_id` = `workspaces`.`id` + ORDER BY `gw`.`updated_at` DESC + LIMIT 1 + ), + `active_branch` = ( + SELECT `gw`.`active_branch` + FROM `group_workspaces` AS `gw` + WHERE `gw`.`workspace_id` = `workspaces`.`id` + ORDER BY `gw`.`updated_at` DESC + LIMIT 1 + ) +WHERE EXISTS ( + SELECT 1 + FROM `group_workspaces` AS `gw` + WHERE `gw`.`workspace_id` = `workspaces`.`id` +);--> statement-breakpoint +ALTER TABLE `group_workspaces` DROP COLUMN `active_repo`;--> statement-breakpoint +ALTER TABLE `group_workspaces` DROP COLUMN `active_branch`; diff --git a/drizzle/0014_steady_korvac.sql b/drizzle/0014_steady_korvac.sql new file mode 100644 index 0000000..4b7ecca --- /dev/null +++ b/drizzle/0014_steady_korvac.sql @@ -0,0 +1,7 @@ +CREATE TABLE `feishu_bot_groups` ( + `chat_id` text PRIMARY KEY NOT NULL, + `channel_id` text NOT NULL, + `chat_name` text NOT NULL, + `creator_open_id` text NOT NULL, + `created_at` integer NOT NULL +); diff --git a/drizzle/0015_closed_loki.sql b/drizzle/0015_closed_loki.sql new file mode 100644 index 0000000..04ccaf8 --- /dev/null +++ b/drizzle/0015_closed_loki.sql @@ -0,0 +1 @@ +ALTER TABLE `feishu_threads` ADD `auto_respond` integer DEFAULT 0 NOT NULL; \ No newline at end of file diff --git a/drizzle/0016_fuzzy_gressill.sql b/drizzle/0016_fuzzy_gressill.sql new file mode 100644 index 0000000..7bf9c49 --- /dev/null +++ b/drizzle/0016_fuzzy_gressill.sql @@ -0,0 +1,2 @@ +ALTER TABLE `workspaces` ADD `last_active_at` integer DEFAULT 0 NOT NULL;--> statement-breakpoint +UPDATE `workspaces` SET `last_active_at` = `updated_at`; diff --git a/drizzle/meta/0010_snapshot.json b/drizzle/meta/0010_snapshot.json index 5da7bb6..4fba971 100644 --- a/drizzle/meta/0010_snapshot.json +++ b/drizzle/meta/0010_snapshot.json @@ -248,4 +248,4 @@ "internal": { "indexes": {} } -} \ No newline at end of file +} diff --git a/drizzle/meta/0011_snapshot.json b/drizzle/meta/0011_snapshot.json new file mode 100644 index 0000000..296216d --- /dev/null +++ b/drizzle/meta/0011_snapshot.json @@ -0,0 +1,317 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "9c5034a3-52eb-43ee-a6c8-f2d11a99d8b6", + "prevId": "44d9caba-533b-42eb-9eda-12fea8b19954", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_path": { + "name": "workspace_path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0012_snapshot.json b/drizzle/meta/0012_snapshot.json new file mode 100644 index 0000000..a5d250b --- /dev/null +++ b/drizzle/meta/0012_snapshot.json @@ -0,0 +1,370 @@ +{ + "id": "224de30f-7d66-48ff-8940-1737e3db056e", + "prevId": "9c5034a3-52eb-43ee-a6c8-f2d11a99d8b6", + "version": "6", + "dialect": "sqlite", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspaces": { + "name": "workspaces", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspaces_path_unique": { + "name": "workspaces_path_unique", + "columns": [ + "path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0013_snapshot.json b/drizzle/meta/0013_snapshot.json new file mode 100644 index 0000000..5f9ec07 --- /dev/null +++ b/drizzle/meta/0013_snapshot.json @@ -0,0 +1,370 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "8d12163c-11da-4e53-b925-55107b8e5832", + "prevId": "224de30f-7d66-48ff-8940-1737e3db056e", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspaces": { + "name": "workspaces", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspaces_path_unique": { + "name": "workspaces_path_unique", + "columns": [ + "path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0014_snapshot.json b/drizzle/meta/0014_snapshot.json new file mode 100644 index 0000000..cb0d772 --- /dev/null +++ b/drizzle/meta/0014_snapshot.json @@ -0,0 +1,415 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "da37cbce-6bd1-4f48-8180-8f958e06cd7c", + "prevId": "8d12163c-11da-4e53-b925-55107b8e5832", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspaces": { + "name": "workspaces", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspaces_path_unique": { + "name": "workspaces_path_unique", + "columns": [ + "path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_bot_groups": { + "name": "feishu_bot_groups", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_name": { + "name": "chat_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_open_id": { + "name": "creator_open_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0015_snapshot.json b/drizzle/meta/0015_snapshot.json new file mode 100644 index 0000000..2048d09 --- /dev/null +++ b/drizzle/meta/0015_snapshot.json @@ -0,0 +1,423 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "53369f63-7a3f-4ee0-ad17-377fad384943", + "prevId": "da37cbce-6bd1-4f48-8180-8f958e06cd7c", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspaces": { + "name": "workspaces", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspaces_path_unique": { + "name": "workspaces_path_unique", + "columns": [ + "path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_bot_groups": { + "name": "feishu_bot_groups", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_name": { + "name": "chat_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_open_id": { + "name": "creator_open_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto_respond": { + "name": "auto_respond", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0016_snapshot.json b/drizzle/meta/0016_snapshot.json new file mode 100644 index 0000000..802131b --- /dev/null +++ b/drizzle/meta/0016_snapshot.json @@ -0,0 +1,430 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "1c0c058a-c700-4e8a-b925-a2cd0e6f57dd", + "prevId": "53369f63-7a3f-4ee0-ad17-377fad384943", + "tables": { + "group_workspaces": { + "name": "group_workspaces", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sessions": { + "name": "sessions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "agent_type": { + "name": "agent_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cwd": { + "name": "cwd", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "first_message": { + "name": "first_message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "runner_session_id": { + "name": "runner_session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "handoff": { + "name": "handoff", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "last_message_created_at": { + "name": "last_message_created_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workspaces": { + "name": "workspaces", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "active_repo": { + "name": "active_repo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "active_branch": { + "name": "active_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_active_at": { + "name": "last_active_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "workspaces_path_unique": { + "name": "workspaces_path_unique", + "columns": [ + "path" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "scheduled_tasks": { + "name": "scheduled_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "instruction": { + "name": "instruction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "schedule": { + "name": "schedule", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "tasks": { + "name": "tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_tasks_session_id": { + "name": "idx_tasks_session_id", + "columns": [ + "session_id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_bot_groups": { + "name": "feishu_bot_groups", + "columns": { + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chat_name": { + "name": "chat_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_open_id": { + "name": "creator_open_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feishu_threads": { + "name": "feishu_threads", + "columns": { + "thread_id": { + "name": "thread_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "auto_respond": { + "name": "auto_respond", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index bc1f2c5..054f025 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -78,6 +78,48 @@ "when": 1778341150681, "tag": "0010_remarkable_malice", "breakpoints": true + }, + { + "idx": 11, + "version": "6", + "when": 1776319736541, + "tag": "0011_lean_enchantress", + "breakpoints": true + }, + { + "idx": 12, + "version": "6", + "when": 1776407449569, + "tag": "0012_workspace_ids", + "breakpoints": true + }, + { + "idx": 13, + "version": "6", + "when": 1776408029760, + "tag": "0013_workspace_active_state", + "breakpoints": true + }, + { + "idx": 14, + "version": "6", + "when": 1776695439707, + "tag": "0014_steady_korvac", + "breakpoints": true + }, + { + "idx": 15, + "version": "6", + "when": 1776842966838, + "tag": "0015_closed_loki", + "breakpoints": true + }, + { + "idx": 16, + "version": "6", + "when": 1776932708363, + "tag": "0016_fuzzy_gressill", + "breakpoints": true } ] -} \ No newline at end of file +} diff --git a/package.json b/package.json index 5061fca..9623a96 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "check:types": "tsc --noEmit", "clean:data": "rm -rf user-home/data && rm -rf user-home/sessions", "dev": "concurrently \"bun run dev:server\" \"bun run dev:web\"", - "dev:server": "bun run index.ts", + "dev:server": "bun --watch run index.ts", "dev:web": "cd web && bun run dev", + "start:server": "bun run index.ts", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", "prepare": "husky" @@ -47,6 +48,7 @@ "hono": "^4.12.5", "pino": "^10.3.1", "pino-pretty": "^13.1.3", - "uuid": "^13.0.0" + "uuid": "^13.0.0", + "yaml": "^2.8.3" } } \ No newline at end of file diff --git a/scripts/down.sh b/scripts/down.sh index 9877b02..71dab7a 100755 --- a/scripts/down.sh +++ b/scripts/down.sh @@ -8,15 +8,20 @@ GRACEFUL_WAIT_TICKS=10 # 10 × 0.5s = 5 seconds EXIT_CODE=0 # Expected command patterns per process name -declare -A EXPECTED_CMD -EXPECTED_CMD[server]="bun run dev:server" -EXPECTED_CMD[web]="bun run dev:web" +expected_cmd_for() { + case "$1" in + server) echo "bun run start:server" ;; + web) echo "bun run dev:web" ;; + *) echo "" ;; + esac +} # Verify PID belongs to the expected process is_our_process() { local pid="$1" local name="$2" - local expected="${EXPECTED_CMD[$name]:-}" + local expected + expected="$(expected_cmd_for "$name")" if [ -z "$expected" ]; then return 0 # no pattern to match, assume ours @@ -30,6 +35,43 @@ is_our_process() { return 1 } +# Recursively collect a PID and all of its descendants, leaves first. +# `bun run