@hasna/bridge 0.1.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.
@@ -0,0 +1,110 @@
1
+ export declare const CONFIG_VERSION: 1;
2
+ export declare const CHANNEL_KINDS: readonly ["telegram", "console", "webhook", "imessage"];
3
+ export type ChannelKind = (typeof CHANNEL_KINDS)[number];
4
+ export declare const AGENT_KINDS: readonly ["codewith", "claude", "aicopilot", "shell"];
5
+ export type AgentKind = (typeof AGENT_KINDS)[number];
6
+ export interface BaseChannelConfig {
7
+ id: string;
8
+ kind: ChannelKind;
9
+ label?: string;
10
+ enabled?: boolean;
11
+ }
12
+ export interface TelegramChannelConfig extends BaseChannelConfig {
13
+ kind: "telegram";
14
+ botTokenEnv?: string;
15
+ defaultChatId?: string;
16
+ allowedChatIds?: string[];
17
+ allowAllChats?: boolean;
18
+ pollTimeoutSeconds?: number;
19
+ }
20
+ export interface ConsoleChannelConfig extends BaseChannelConfig {
21
+ kind: "console";
22
+ }
23
+ export interface WebhookChannelConfig extends BaseChannelConfig {
24
+ kind: "webhook";
25
+ secretEnv?: string;
26
+ }
27
+ export interface IMessageChannelConfig extends BaseChannelConfig {
28
+ kind: "imessage";
29
+ account?: string;
30
+ }
31
+ export type ChannelConfig = TelegramChannelConfig | ConsoleChannelConfig | WebhookChannelConfig | IMessageChannelConfig;
32
+ export interface ProfileConfig {
33
+ id: string;
34
+ agentKind: AgentKind;
35
+ label?: string;
36
+ authProfile?: string;
37
+ cwd?: string;
38
+ home?: string;
39
+ command?: string;
40
+ args?: string[];
41
+ env?: Record<string, string>;
42
+ }
43
+ export interface AgentConfig {
44
+ id: string;
45
+ kind: AgentKind;
46
+ label?: string;
47
+ profileId?: string;
48
+ command?: string;
49
+ args?: string[];
50
+ cwd?: string;
51
+ env?: Record<string, string>;
52
+ timeoutMs?: number;
53
+ }
54
+ export interface RouteMatch {
55
+ chatIds?: string[];
56
+ textRegex?: string;
57
+ }
58
+ export interface RouteConfig {
59
+ id: string;
60
+ fromChannel: string;
61
+ toAgent: string;
62
+ responseChannel?: string;
63
+ enabled?: boolean;
64
+ match?: RouteMatch;
65
+ }
66
+ export interface BridgeConfig {
67
+ version: typeof CONFIG_VERSION;
68
+ channels: Record<string, ChannelConfig>;
69
+ profiles: Record<string, ProfileConfig>;
70
+ agents: Record<string, AgentConfig>;
71
+ routes: RouteConfig[];
72
+ }
73
+ export interface BridgeMessage {
74
+ id: string;
75
+ channelId: string;
76
+ text: string;
77
+ chatId?: string;
78
+ from?: string;
79
+ receivedAt: string;
80
+ raw?: unknown;
81
+ }
82
+ export interface AgentRunInput {
83
+ message: BridgeMessage;
84
+ route: RouteConfig;
85
+ }
86
+ export interface AgentRunResult {
87
+ agentId: string;
88
+ command: string[];
89
+ cwd?: string;
90
+ exitCode: number | null;
91
+ stdout: string;
92
+ stderr: string;
93
+ timedOut: boolean;
94
+ }
95
+ export interface RoutedMessageResult {
96
+ route: RouteConfig;
97
+ agent: AgentRunResult;
98
+ deliveredResponse?: boolean;
99
+ }
100
+ export interface DoctorCheck {
101
+ name: string;
102
+ ok: boolean;
103
+ detail?: string;
104
+ }
105
+ export interface DoctorReport {
106
+ ok: boolean;
107
+ configPath: string;
108
+ checks: DoctorCheck[];
109
+ }
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ # Bridge Architecture
2
+
3
+ `bridge` separates channel connectors from agent adapters.
4
+
5
+ Channels own external transport details such as Telegram bot tokens, chat IDs,
6
+ webhooks, or future iMessage transport. Agents own local execution details such
7
+ as Codewith auth profiles, Claude profile homes, AIcopilot state roots, command
8
+ arguments, cwd, and environment. Routes connect one channel to one agent.
9
+
10
+ The package deliberately keeps Telegram-specific behavior out of Codewith,
11
+ Claude, and AIcopilot integrations. Agent adapters receive plain text prompts
12
+ and return stdout/stderr plus process metadata. Channel connectors decide how
13
+ to receive and deliver messages.
14
+
15
+ ## Data Model
16
+
17
+ - `channels`: external message transports.
18
+ - `profiles`: reusable identity/state settings for an agent family.
19
+ - `agents`: runnable targets, usually pointing at one profile.
20
+ - `routes`: mapping rules from channel messages to agents.
21
+
22
+ ## Profile Model
23
+
24
+ Codewith profiles use `authProfile` and render as `codewith --auth-profile
25
+ <name> --cd <cwd> exec <prompt>`.
26
+
27
+ Claude profiles can use `home` or custom env vars so multiple accounts do not
28
+ share local state.
29
+
30
+ AIcopilot profiles currently use cwd/env/command isolation. The target repo
31
+ work dispatched on spark02 is expected to add or document first-class profile
32
+ support.
33
+
34
+ ## Telegram
35
+
36
+ The first connector uses Telegram Bot API `getUpdates` long polling and
37
+ `sendMessage`. Production deployments should move high-volume bots to webhooks,
38
+ but long polling is the right baseline for local agent machines and early
39
+ testing.
40
+
41
+ Telegram channels fail closed unless `allowedChatIds` are configured or
42
+ `allowAllChats` is explicitly enabled. Channel `allowedChatIds` are enforced
43
+ before route matching. Routes can also add narrower `match.chatIds` filters, but
44
+ they cannot expand beyond the channel allowlist.
45
+
46
+ Long-poll offsets are persisted in a private state file so process restarts do
47
+ not replay already-seen updates and re-run agents.
@@ -0,0 +1,49 @@
1
+ {
2
+ "version": 1,
3
+ "channels": {
4
+ "telegram-main": {
5
+ "id": "telegram-main",
6
+ "kind": "telegram",
7
+ "enabled": true,
8
+ "botTokenEnv": "TELEGRAM_BOT_TOKEN",
9
+ "allowedChatIds": ["123456789"],
10
+ "allowAllChats": false
11
+ }
12
+ },
13
+ "profiles": {
14
+ "codewith-account001": {
15
+ "id": "codewith-account001",
16
+ "agentKind": "codewith",
17
+ "authProfile": "account001",
18
+ "cwd": "/Users/hasna"
19
+ },
20
+ "claude-account001": {
21
+ "id": "claude-account001",
22
+ "agentKind": "claude",
23
+ "home": "/Users/hasna/.hasna/accounts/profiles/claude/account001"
24
+ },
25
+ "aicopilot-main": {
26
+ "id": "aicopilot-main",
27
+ "agentKind": "aicopilot",
28
+ "cwd": "/Users/hasna"
29
+ }
30
+ },
31
+ "agents": {
32
+ "codewith": {
33
+ "id": "codewith",
34
+ "kind": "codewith",
35
+ "profileId": "codewith-account001"
36
+ }
37
+ },
38
+ "routes": [
39
+ {
40
+ "id": "telegram-codewith",
41
+ "fromChannel": "telegram-main",
42
+ "toAgent": "codewith",
43
+ "enabled": true,
44
+ "match": {
45
+ "chatIds": ["123456789"]
46
+ }
47
+ }
48
+ ]
49
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@hasna/bridge",
3
+ "version": "0.1.0",
4
+ "description": "Agent messaging bridge for Telegram and other channels",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "bridge": "dist/cli/index.js",
10
+ "bridge-mcp": "dist/mcp/index.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "docs",
21
+ "examples",
22
+ "LICENSE",
23
+ "README.md"
24
+ ],
25
+ "scripts": {
26
+ "build": "rm -rf dist && bun build src/cli/index.ts --outdir dist/cli --target bun --external @modelcontextprotocol/sdk && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk && bun build src/index.ts --outdir dist --target bun && tsc -p tsconfig.build.json",
27
+ "typecheck": "tsc --noEmit",
28
+ "test": "bun test",
29
+ "dev:cli": "bun run src/cli/index.ts",
30
+ "dev:mcp": "bun run src/mcp/index.ts",
31
+ "prepublishOnly": "bun run build",
32
+ "postinstall": "bun -e \"const fs=require('node:fs');const path=require('node:path');const dir=path.join(process.env.HOME||process.cwd(),'.hasna','bridge');fs.mkdirSync(dir,{recursive:true,mode:0o700});try{fs.chmodSync(dir,0o700)}catch{}\""
33
+ },
34
+ "keywords": [
35
+ "bridge",
36
+ "telegram",
37
+ "messaging",
38
+ "agents",
39
+ "codewith",
40
+ "claude",
41
+ "aicopilot",
42
+ "mcp",
43
+ "cli"
44
+ ],
45
+ "publishConfig": {
46
+ "registry": "https://registry.npmjs.org",
47
+ "access": "public"
48
+ },
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/hasna/bridge.git"
52
+ },
53
+ "homepage": "https://github.com/hasna/bridge",
54
+ "bugs": {
55
+ "url": "https://github.com/hasna/bridge/issues"
56
+ },
57
+ "engines": {
58
+ "bun": ">=1.0.0"
59
+ },
60
+ "author": "Andrei Hasna <andrei@hasna.com>",
61
+ "license": "Apache-2.0",
62
+ "dependencies": {
63
+ "@modelcontextprotocol/sdk": "^1.29.0",
64
+ "commander": "^13.1.0",
65
+ "zod": "^3.25.76"
66
+ },
67
+ "devDependencies": {
68
+ "@types/bun": "^1.2.4",
69
+ "typescript": "^5.7.3"
70
+ }
71
+ }