bazilion 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +372 -22
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +18461 -1802
- package/dist/daemon.js.map +1 -1
- package/dist/migrations/0001_init.sql +179 -0
- package/dist/migrations/0002_profile_groups.sql +39 -0
- package/dist/migrations/0003_agent_telegram.sql +40 -0
- package/dist/migrations/0004_agent_mirror_mode.sql +17 -0
- package/dist/migrations/0005_group_topic_name_format.sql +15 -0
- package/dist/migrations/0006_telegram_acl.sql +18 -0
- package/dist/worker.js +44 -4
- package/dist/worker.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
-- Bazilion initial schema (consolidated, post-IPC + secrets-in-DB cleanup).
|
|
2
|
+
--
|
|
3
|
+
-- The daemon is the sole owner of `~/.bazilion/`. All state — entity
|
|
4
|
+
-- metadata, inbox, scheduler, web tokens, encrypted secrets, plaintext
|
|
5
|
+
-- config — lives in this single SQLite file. The only other file at the
|
|
6
|
+
-- bazilion home root is `auth.json`: a tiny bootstrap shared by the daemon
|
|
7
|
+
-- (which uses its `token` as the PBKDF2 seed for the `secrets` table) and
|
|
8
|
+
-- the CLI (which uses the same token as its loopback bearer).
|
|
9
|
+
--
|
|
10
|
+
-- On-disk layout owned by the daemon:
|
|
11
|
+
-- ~/.bazilion/bazilion.db
|
|
12
|
+
-- ~/.bazilion/groups/<slug>/ — group root, mounted as cwd; may be a
|
|
13
|
+
-- symlink for "agents working on my
|
|
14
|
+
-- existing project tree" use cases
|
|
15
|
+
-- /memory/ — qmd index for the group (shared by
|
|
16
|
+
-- all member agents)
|
|
17
|
+
-- ~/.bazilion/agents/<id>/ — agent's private home (NEVER inside
|
|
18
|
+
-- the group tree, so the cwd-rooted
|
|
19
|
+
-- coding tools can't see/clobber it)
|
|
20
|
+
-- /sessions/*.jsonl — pi transcripts
|
|
21
|
+
-- ~/.bazilion/profiles/<id>/ — profile templates
|
|
22
|
+
-- ~/.bazilion/skills/<name>/ — installed skills
|
|
23
|
+
-- ~/.bazilion/logs/ — daemon logs
|
|
24
|
+
|
|
25
|
+
-- Groups are collaboration contexts: one filesystem root, one USER.md, one
|
|
26
|
+
-- roster of member agents. The id IS the slug IS the directory name under
|
|
27
|
+
-- `~/.bazilion/groups/`. No `path` column — paths derive from id.
|
|
28
|
+
-- `user_md` is read-only context about the human (edited via web UI; never
|
|
29
|
+
-- exposed as a file the agent could clobber via `edit`/`write`).
|
|
30
|
+
CREATE TABLE groups (
|
|
31
|
+
id TEXT PRIMARY KEY,
|
|
32
|
+
name TEXT NOT NULL,
|
|
33
|
+
user_md TEXT NOT NULL DEFAULT '',
|
|
34
|
+
created_at INTEGER NOT NULL
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
-- Profiles are agent templates. `dir` is the on-disk directory for the
|
|
38
|
+
-- profile's SOUL.md / IDENTITY.md / etc. master files, derived from id.
|
|
39
|
+
-- `skills_mode = 'all'` attaches every installed skill at spawn;
|
|
40
|
+
-- `'selected'` attaches only those listed in `profile_default_skills`.
|
|
41
|
+
CREATE TABLE profiles (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
name TEXT NOT NULL,
|
|
44
|
+
dir TEXT NOT NULL,
|
|
45
|
+
default_model TEXT NOT NULL,
|
|
46
|
+
skills_mode TEXT NOT NULL DEFAULT 'selected' CHECK (skills_mode IN ('all','selected')),
|
|
47
|
+
created_at INTEGER NOT NULL,
|
|
48
|
+
updated_at INTEGER NOT NULL
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
CREATE TABLE profile_default_skills (
|
|
52
|
+
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE CASCADE,
|
|
53
|
+
skill_name TEXT NOT NULL,
|
|
54
|
+
PRIMARY KEY (profile_id, skill_name)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
-- Agents have exactly one group. `dir` is the agent's private home,
|
|
58
|
+
-- ~/.bazilion/agents/<id>/ — strictly outside the group tree so that
|
|
59
|
+
-- pi's coding tools (rooted at the group dir) can't reach into it.
|
|
60
|
+
-- `reasoning_level` feeds pi-ai's streamSimple `reasoning` option;
|
|
61
|
+
-- 'medium' is the sensible default.
|
|
62
|
+
CREATE TABLE agents (
|
|
63
|
+
id TEXT PRIMARY KEY,
|
|
64
|
+
profile_id TEXT NOT NULL REFERENCES profiles(id),
|
|
65
|
+
name TEXT NOT NULL,
|
|
66
|
+
model_override TEXT,
|
|
67
|
+
status TEXT NOT NULL CHECK (status IN ('idle','running','archived')),
|
|
68
|
+
dir TEXT NOT NULL,
|
|
69
|
+
reasoning_level TEXT NOT NULL DEFAULT 'medium',
|
|
70
|
+
group_id TEXT NOT NULL REFERENCES groups(id) ON DELETE RESTRICT,
|
|
71
|
+
created_at INTEGER NOT NULL,
|
|
72
|
+
archived_at INTEGER
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
CREATE TABLE agent_skills (
|
|
76
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
77
|
+
skill_name TEXT NOT NULL,
|
|
78
|
+
attached_at INTEGER NOT NULL,
|
|
79
|
+
PRIMARY KEY (agent_id, skill_name)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
-- Periodic / scheduled wake-up triggers. The scheduler picks rows whose
|
|
83
|
+
-- next-fire time has elapsed and kicks off a turn with `message` as the
|
|
84
|
+
-- user input.
|
|
85
|
+
--
|
|
86
|
+
-- kind='interval' → interval_sec holds seconds between fires (cron_expr NULL)
|
|
87
|
+
-- kind='cron' → cron_expr holds a 5-field cron expression (interval_sec NULL)
|
|
88
|
+
--
|
|
89
|
+
-- last_fired_at is bumped *before* the run kicks off so a daemon restart
|
|
90
|
+
-- mid-fire doesn't double-trigger.
|
|
91
|
+
CREATE TABLE agent_triggers (
|
|
92
|
+
id TEXT PRIMARY KEY,
|
|
93
|
+
agent_id TEXT NOT NULL REFERENCES agents(id) ON DELETE CASCADE,
|
|
94
|
+
kind TEXT NOT NULL CHECK (kind IN ('interval','cron')),
|
|
95
|
+
interval_sec INTEGER,
|
|
96
|
+
cron_expr TEXT,
|
|
97
|
+
message TEXT NOT NULL,
|
|
98
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
99
|
+
last_fired_at INTEGER,
|
|
100
|
+
created_at INTEGER NOT NULL
|
|
101
|
+
);
|
|
102
|
+
CREATE INDEX agent_triggers_agent ON agent_triggers(agent_id);
|
|
103
|
+
CREATE INDEX agent_triggers_enabled ON agent_triggers(enabled) WHERE enabled = 1;
|
|
104
|
+
|
|
105
|
+
-- Inter-agent inbox. The scheduler's auto-deliver loop polls
|
|
106
|
+
-- `messages_to_unread` to fan out wakeup turns; the messaging tools insert
|
|
107
|
+
-- here when one agent sends another a message.
|
|
108
|
+
CREATE TABLE messages (
|
|
109
|
+
id TEXT PRIMARY KEY,
|
|
110
|
+
from_agent_id TEXT NOT NULL REFERENCES agents(id),
|
|
111
|
+
to_agent_id TEXT NOT NULL REFERENCES agents(id),
|
|
112
|
+
reply_to TEXT REFERENCES messages(id),
|
|
113
|
+
payload TEXT NOT NULL,
|
|
114
|
+
created_at INTEGER NOT NULL,
|
|
115
|
+
read_at INTEGER
|
|
116
|
+
);
|
|
117
|
+
CREATE INDEX messages_to_unread ON messages(to_agent_id) WHERE read_at IS NULL;
|
|
118
|
+
|
|
119
|
+
-- Per-skill import provenance. Skills live on disk under ~/.bazilion/skills/<name>/;
|
|
120
|
+
-- this table records where each was imported from and when.
|
|
121
|
+
CREATE TABLE skill_meta (
|
|
122
|
+
name TEXT PRIMARY KEY,
|
|
123
|
+
source TEXT,
|
|
124
|
+
imported_at INTEGER
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
-- Per-client web tokens. Each row stores SHA-256(token) hex; the plaintext
|
|
128
|
+
-- is returned exactly once at creation time and never persisted in this
|
|
129
|
+
-- table. The CLI's bootstrap token is one row here — its plaintext lives
|
|
130
|
+
-- in `~/.bazilion/auth.json` so both the daemon (PBKDF2 seed for the
|
|
131
|
+
-- secrets table) and the CLI (loopback bearer) can read it.
|
|
132
|
+
-- `revoked_at` is a soft-delete marker to keep audit trail intact.
|
|
133
|
+
CREATE TABLE web_tokens (
|
|
134
|
+
id TEXT PRIMARY KEY,
|
|
135
|
+
label TEXT NOT NULL,
|
|
136
|
+
token_hash TEXT NOT NULL UNIQUE,
|
|
137
|
+
created_at INTEGER NOT NULL,
|
|
138
|
+
last_used_at INTEGER,
|
|
139
|
+
revoked_at INTEGER
|
|
140
|
+
);
|
|
141
|
+
CREATE INDEX web_tokens_active ON web_tokens(token_hash) WHERE revoked_at IS NULL;
|
|
142
|
+
|
|
143
|
+
-- Curated list of models per provider. Drives the model dropdowns in
|
|
144
|
+
-- profile creation and agent spawn/edit forms.
|
|
145
|
+
CREATE TABLE provider_models (
|
|
146
|
+
provider TEXT NOT NULL,
|
|
147
|
+
model TEXT NOT NULL,
|
|
148
|
+
added_at INTEGER NOT NULL,
|
|
149
|
+
PRIMARY KEY (provider, model)
|
|
150
|
+
);
|
|
151
|
+
CREATE INDEX idx_provider_models_provider ON provider_models (provider);
|
|
152
|
+
|
|
153
|
+
-- Admin-toggled enabled state per provider.
|
|
154
|
+
CREATE TABLE provider_state (
|
|
155
|
+
provider_id TEXT NOT NULL PRIMARY KEY,
|
|
156
|
+
enabled INTEGER NOT NULL DEFAULT 0,
|
|
157
|
+
updated_at INTEGER NOT NULL
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
-- Encrypted secrets. AES-256-GCM envelopes (salt+iv+tag+data hex JSON),
|
|
161
|
+
-- one row per env-var-shaped key (`ANTHROPIC_API_KEY`, `OPENAI_CODEX_OAUTH`, …).
|
|
162
|
+
-- The encryption key is derived from the bootstrap web token (PBKDF2-SHA256,
|
|
163
|
+
-- 100k iterations) — same crypto as the previous file-based secrets.enc,
|
|
164
|
+
-- now atomic with the rest of the DB.
|
|
165
|
+
CREATE TABLE secrets (
|
|
166
|
+
key TEXT PRIMARY KEY,
|
|
167
|
+
envelope TEXT NOT NULL,
|
|
168
|
+
updated_at INTEGER NOT NULL
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
-- Plaintext config. Same env-var-shaped keys as secrets, but for values
|
|
172
|
+
-- that don't need confidentiality (server URLs, region slugs, project IDs).
|
|
173
|
+
-- The application layer enforces a CONFIG_KEYS allowlist on writes so a
|
|
174
|
+
-- typo can't put a secret in this table.
|
|
175
|
+
CREATE TABLE config (
|
|
176
|
+
key TEXT PRIMARY KEY,
|
|
177
|
+
value TEXT NOT NULL,
|
|
178
|
+
updated_at INTEGER NOT NULL
|
|
179
|
+
);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- Profile groups — preconfigured team templates. A ProfileGroup captures
|
|
2
|
+
-- the recipe for a team (ordered slots, each pointing at a Profile with
|
|
3
|
+
-- optional per-slot overrides) so an operator can replay it with a single
|
|
4
|
+
-- spawn call instead of clicking through agent-create N times per project.
|
|
5
|
+
--
|
|
6
|
+
-- Strictly additive: the single-profile `POST /api/agents` spawn path is
|
|
7
|
+
-- untouched. Profile groups bundle existing primitives (profiles, groups,
|
|
8
|
+
-- agents), they don't replace them.
|
|
9
|
+
--
|
|
10
|
+
-- Spawn semantics live in apps/daemon/src/core/profile-group/spawn.ts.
|
|
11
|
+
-- See docs/backlog/todo/BAZ-002-profile-groups.md for the full spec.
|
|
12
|
+
|
|
13
|
+
CREATE TABLE profile_groups (
|
|
14
|
+
id TEXT PRIMARY KEY, -- slug, e.g. "platform-team"
|
|
15
|
+
name TEXT NOT NULL, -- display name
|
|
16
|
+
user_md TEXT, -- optional starter USER.md; seeded only into a freshly-created target group (pre-existing groups are left alone — see Decision #5)
|
|
17
|
+
created_at INTEGER NOT NULL,
|
|
18
|
+
updated_at INTEGER NOT NULL
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- Member ordering uses an explicit `position` column rather than insertion
|
|
22
|
+
-- order so the spawn loop is deterministic and rollback can identify which
|
|
23
|
+
-- members succeeded. PK includes position so the same template can have
|
|
24
|
+
-- multiple members pointing at the same profile (e.g. "two reviewers" —
|
|
25
|
+
-- duplicate agent_name values are intentionally accepted; the spawn op
|
|
26
|
+
-- auto-suffixes collisions with `-2`, `-3`, ... at spawn time).
|
|
27
|
+
--
|
|
28
|
+
-- `ON DELETE RESTRICT` on profile_id prevents deleting a profile that a
|
|
29
|
+
-- profile-group member still references; the existing single-profile delete
|
|
30
|
+
-- keeps working unchanged because it never had a referrer before.
|
|
31
|
+
CREATE TABLE profile_group_members (
|
|
32
|
+
profile_group_id TEXT NOT NULL REFERENCES profile_groups(id) ON DELETE CASCADE,
|
|
33
|
+
position INTEGER NOT NULL,
|
|
34
|
+
profile_id TEXT NOT NULL REFERENCES profiles(id) ON DELETE RESTRICT,
|
|
35
|
+
agent_name TEXT NOT NULL, -- e.g. "planner", "reviewer"
|
|
36
|
+
model_override TEXT, -- nullable; falls back to profile.default_model
|
|
37
|
+
reasoning_level TEXT, -- nullable; falls back to spawn default 'medium'
|
|
38
|
+
PRIMARY KEY (profile_group_id, position)
|
|
39
|
+
);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- Telegram integration columns. Step 1 of the docs/telegram.md plan adds the
|
|
2
|
+
-- schema only; the bot singleton, polling loop, and routing helpers land in
|
|
3
|
+
-- subsequent steps. None of these columns are populated yet — they sit empty
|
|
4
|
+
-- until the live bot in Step 2 starts persisting topic ids on first traffic.
|
|
5
|
+
--
|
|
6
|
+
-- agents.telegram_topic_id — forum-topic message_thread_id; one topic per
|
|
7
|
+
-- agent. Partial unique index below allows
|
|
8
|
+
-- multiple NULLs (unbound agents) but enforces
|
|
9
|
+
-- one-to-one once an id is written.
|
|
10
|
+
-- agents.telegram_topic_name_locked — sticky bit set when a human renames the
|
|
11
|
+
-- topic in Telegram; once set, bazilion stops
|
|
12
|
+
-- propagating agent/group renames to that topic.
|
|
13
|
+
-- agents.telegram_icon_emoji — per-agent override of the profile-derived
|
|
14
|
+
-- custom-emoji sticker id. Lookup at topic
|
|
15
|
+
-- creation: agents.* → profiles.* → null.
|
|
16
|
+
-- Survives topic delete + recreate, unlike
|
|
17
|
+
-- a customization that only lived in Telegram.
|
|
18
|
+
-- groups.telegram_icon_color — Telegram's 6-color enum slot allocated to
|
|
19
|
+
-- this group on first-traffic. Red is reserved
|
|
20
|
+
-- for the service chat, so groups round-robin
|
|
21
|
+
-- over the remaining 5.
|
|
22
|
+
-- profiles.telegram_icon_emoji — curated default sticker id from
|
|
23
|
+
-- getForumTopicIconStickers, per built-in
|
|
24
|
+
-- profile. Seeded for built-ins, NULL for
|
|
25
|
+
-- custom profiles (which render color-only).
|
|
26
|
+
|
|
27
|
+
ALTER TABLE agents ADD COLUMN telegram_topic_id INTEGER;
|
|
28
|
+
ALTER TABLE agents ADD COLUMN telegram_topic_name_locked INTEGER NOT NULL DEFAULT 0;
|
|
29
|
+
ALTER TABLE agents ADD COLUMN telegram_icon_emoji TEXT;
|
|
30
|
+
|
|
31
|
+
ALTER TABLE groups ADD COLUMN telegram_icon_color INTEGER;
|
|
32
|
+
|
|
33
|
+
ALTER TABLE profiles ADD COLUMN telegram_icon_emoji TEXT;
|
|
34
|
+
|
|
35
|
+
-- Partial unique index: enforces one-to-one mapping between agents and topic
|
|
36
|
+
-- ids without blocking many unbound agents (SQLite treats NULLs as distinct
|
|
37
|
+
-- in unique indexes, but being explicit avoids surprise if that ever changes).
|
|
38
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agents_telegram_topic_id
|
|
39
|
+
ON agents(telegram_topic_id)
|
|
40
|
+
WHERE telegram_topic_id IS NOT NULL;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Per-agent Telegram outbound-mirror verbosity.
|
|
2
|
+
--
|
|
3
|
+
-- 'minimal' (default): mirror only the assistant's final message text to
|
|
4
|
+
-- the agent's bound forum topic. Cleanest conversation
|
|
5
|
+
-- feel; what most operators want.
|
|
6
|
+
-- 'verbose': also mirror short tool-call summary lines so the
|
|
7
|
+
-- topic shows the agent's reasoning steps. Helpful
|
|
8
|
+
-- while iterating on a misbehaving agent; noisy in
|
|
9
|
+
-- steady state.
|
|
10
|
+
--
|
|
11
|
+
-- The column has no effect on agents without a bound topic. Step 6 picks
|
|
12
|
+
-- the value up when materializing each ChatFrame; Step 7's CLI + web UI
|
|
13
|
+
-- surfaces let operators flip it per-agent.
|
|
14
|
+
|
|
15
|
+
ALTER TABLE agents
|
|
16
|
+
ADD COLUMN telegram_mirror_mode TEXT NOT NULL DEFAULT 'minimal'
|
|
17
|
+
CHECK (telegram_mirror_mode IN ('minimal','verbose'));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Per-group Telegram forum-topic name template.
|
|
2
|
+
--
|
|
3
|
+
-- NULL (default): bazilion composes topic names the built-in way — bare
|
|
4
|
+
-- agent.name for the `default` group, "<group.slug> › <agent.name>" for every
|
|
5
|
+
-- other group (see lib/telegram/naming.ts:topicNameFor).
|
|
6
|
+
-- Non-NULL: an explicit template rendered with the tokens {agent.name},
|
|
7
|
+
-- {group.name}, {group.slug}. Must contain {agent.name} so each agent in the
|
|
8
|
+
-- group still gets a distinct topic title. Validated on write
|
|
9
|
+
-- (lib/telegram/naming.ts:validateTopicNameFormat).
|
|
10
|
+
--
|
|
11
|
+
-- Changing the template re-renders every bound, non-locked topic in the group
|
|
12
|
+
-- via editForumTopic (lib/telegram/topic-rename.ts:syncGroupTopicNames). Topics
|
|
13
|
+
-- a human has renamed (telegram_topic_name_locked = 1) are left untouched.
|
|
14
|
+
|
|
15
|
+
ALTER TABLE groups ADD COLUMN telegram_topic_name_format TEXT;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Per-user Telegram allowlist (Phase 7).
|
|
2
|
+
--
|
|
3
|
+
-- Bootstrap model: TOFU (trust-on-first-use). While this table is empty the
|
|
4
|
+
-- bot is open; the first user to message it is auto-added as 'owner' and
|
|
5
|
+
-- enforcement begins immediately after. Scope: FLAT — an allowlisted user can
|
|
6
|
+
-- do everything (commands + agent chat); anyone not on the list is ignored.
|
|
7
|
+
--
|
|
8
|
+
-- role: 'owner' can manage the allowlist (/allow, /deny) and cannot be removed;
|
|
9
|
+
-- 'member' can use the bot but not manage who else can. At least one owner must
|
|
10
|
+
-- always remain (enforced in the repo + routes).
|
|
11
|
+
|
|
12
|
+
CREATE TABLE IF NOT EXISTS telegram_allowed_users (
|
|
13
|
+
user_id INTEGER PRIMARY KEY,
|
|
14
|
+
username TEXT,
|
|
15
|
+
label TEXT,
|
|
16
|
+
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner','member')),
|
|
17
|
+
added_at INTEGER NOT NULL
|
|
18
|
+
);
|
package/dist/worker.js
CHANGED
|
@@ -32,7 +32,7 @@ import { existsSync as existsSync4, readdirSync } from "fs";
|
|
|
32
32
|
import { join as join3 } from "path";
|
|
33
33
|
|
|
34
34
|
// ../daemon/src/core/db/client.ts
|
|
35
|
-
import { DatabaseSync } from "sqlite";
|
|
35
|
+
import { DatabaseSync } from "node:sqlite";
|
|
36
36
|
|
|
37
37
|
// ../daemon/src/core/db/migrate.ts
|
|
38
38
|
import { readdirSync as readdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
@@ -418,6 +418,36 @@ var SERVICES = [
|
|
|
418
418
|
placeholder: "https://searxng.example.com"
|
|
419
419
|
}
|
|
420
420
|
]
|
|
421
|
+
},
|
|
422
|
+
// --- External integrations (chat bridges, etc) ---
|
|
423
|
+
// Each integration has its own dedicated /config/integrations/* page with
|
|
424
|
+
// workflow-specific UI (preflight health, setup wizard, …). The fields
|
|
425
|
+
// here exist so the keys are allowlisted in the config/secrets stores and
|
|
426
|
+
// surfaced through the generic `PUT /api/config/fields/:envVar` endpoint.
|
|
427
|
+
// Daemon-managed internal state keys (watermarks, derived topic ids) live
|
|
428
|
+
// in repos/config.ts:INTERNAL_CONFIG_KEYS instead, since the user never
|
|
429
|
+
// edits them.
|
|
430
|
+
{
|
|
431
|
+
id: "telegram",
|
|
432
|
+
displayName: "Telegram",
|
|
433
|
+
category: "integration",
|
|
434
|
+
hint: "Forum-supergroup bot for talking to your agents from a phone",
|
|
435
|
+
fields: [
|
|
436
|
+
{
|
|
437
|
+
envVar: "TELEGRAM_BOT_TOKEN",
|
|
438
|
+
kind: "secret",
|
|
439
|
+
label: "Bot token",
|
|
440
|
+
placeholder: "1234567890:ABC...",
|
|
441
|
+
description: "Get one from @BotFather \u2192 /newbot. Disable Privacy Mode in Bot Settings."
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
envVar: "TELEGRAM_CHAT_ID",
|
|
445
|
+
kind: "config",
|
|
446
|
+
label: "Supergroup chat ID",
|
|
447
|
+
placeholder: "-1001234567890",
|
|
448
|
+
description: "Numeric id of the forum-enabled supergroup the bot is admin in."
|
|
449
|
+
}
|
|
450
|
+
]
|
|
421
451
|
}
|
|
422
452
|
];
|
|
423
453
|
var FIELD_INDEX = (() => {
|
|
@@ -431,9 +461,19 @@ var FIELD_INDEX = (() => {
|
|
|
431
461
|
})();
|
|
432
462
|
|
|
433
463
|
// ../daemon/src/core/repos/config.ts
|
|
434
|
-
var
|
|
435
|
-
|
|
436
|
-
|
|
464
|
+
var INTERNAL_CONFIG_KEYS = [
|
|
465
|
+
// Telegram (step 2+): polling watermark + derived topic/message ids.
|
|
466
|
+
"TELEGRAM_LAST_UPDATE_ID",
|
|
467
|
+
"TELEGRAM_SERVICE_TOPIC_ID",
|
|
468
|
+
"TELEGRAM_DIRECTORY_MESSAGE_ID",
|
|
469
|
+
// Phase 5: proposed new chat id after a migrate_to_chat_id event, pending
|
|
470
|
+
// operator confirmation via POST /api/config/telegram/reconnect.
|
|
471
|
+
"TELEGRAM_MIGRATED_CHAT_ID"
|
|
472
|
+
];
|
|
473
|
+
var CONFIG_KEYS = [
|
|
474
|
+
...SERVICES.flatMap((s) => s.fields.filter((f) => f.kind === "config").map((f) => f.envVar)),
|
|
475
|
+
...INTERNAL_CONFIG_KEYS
|
|
476
|
+
];
|
|
437
477
|
var CONFIG_KEY_SET = new Set(CONFIG_KEYS);
|
|
438
478
|
|
|
439
479
|
// ../daemon/src/core/repos/messages.ts
|