@shareai-lab/kode-sdk 1.0.0-beta.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,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventBus = void 0;
4
+ const types_1 = require("../core/types");
5
+ const events_1 = require("events");
6
+ const crypto_1 = require("crypto");
7
+ class EventBus extends events_1.EventEmitter {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.cursor = 0;
11
+ this.timeline = [];
12
+ this.subscribers = new Set();
13
+ }
14
+ setStore(store, sessionId) {
15
+ this.store = store;
16
+ this.sessionId = sessionId;
17
+ }
18
+ emitEvent(event) {
19
+ const cursor = this.cursor++;
20
+ const eventId = (0, crypto_1.randomUUID)();
21
+ const timestamp = Date.now();
22
+ const fullEvent = { ...event, cursor, eventId, timestamp };
23
+ const timeline = { cursor, event: fullEvent };
24
+ this.timeline.push(timeline);
25
+ // Memory management: keep only last 10k events in memory
26
+ if (this.timeline.length > 10000) {
27
+ this.timeline = this.timeline.slice(-5000);
28
+ }
29
+ // Persist to store if configured
30
+ if (this.store && this.sessionId) {
31
+ this.store.appendEvent(this.sessionId, timeline).catch((err) => {
32
+ // Log error but don't block event emission
33
+ console.error('Failed to persist event:', err);
34
+ });
35
+ }
36
+ // Notify all subscribers
37
+ for (const subscriber of this.subscribers) {
38
+ if (subscriber.accepts(fullEvent.type)) {
39
+ subscriber.push(fullEvent);
40
+ }
41
+ }
42
+ // Emit control plane events
43
+ this.emit(event.type, fullEvent);
44
+ return cursor;
45
+ }
46
+ subscribe(opts) {
47
+ const subscriber = new EventSubscriber(opts?.kinds || types_1.MINIMAL_EVENT_KINDS);
48
+ this.subscribers.add(subscriber);
49
+ // Replay past events if since is specified
50
+ if (opts?.since !== undefined) {
51
+ const past = this.timeline.filter((t) => t.cursor >= opts.since);
52
+ for (const t of past) {
53
+ if (subscriber.accepts(t.event.type)) {
54
+ subscriber.push(t.event);
55
+ }
56
+ }
57
+ }
58
+ return {
59
+ [Symbol.asyncIterator]: () => ({
60
+ next: async () => {
61
+ const event = await subscriber.next();
62
+ if (!event) {
63
+ this.subscribers.delete(subscriber);
64
+ return { done: true, value: undefined };
65
+ }
66
+ return { done: false, value: event };
67
+ },
68
+ }),
69
+ };
70
+ }
71
+ getTimeline(since) {
72
+ return since !== undefined ? this.timeline.filter((t) => t.cursor >= since) : this.timeline;
73
+ }
74
+ getCursor() {
75
+ return this.cursor;
76
+ }
77
+ reset() {
78
+ this.cursor = 0;
79
+ this.timeline = [];
80
+ this.subscribers.clear();
81
+ }
82
+ }
83
+ exports.EventBus = EventBus;
84
+ class EventSubscriber {
85
+ constructor(kinds) {
86
+ this.kinds = kinds;
87
+ this.queue = [];
88
+ this.waiting = null;
89
+ this.closed = false;
90
+ }
91
+ accepts(kind) {
92
+ return this.kinds.includes(kind);
93
+ }
94
+ push(event) {
95
+ if (this.closed)
96
+ return;
97
+ if (this.waiting) {
98
+ this.waiting(event);
99
+ this.waiting = null;
100
+ }
101
+ else {
102
+ this.queue.push(event);
103
+ }
104
+ }
105
+ async next() {
106
+ if (this.closed)
107
+ return null;
108
+ if (this.queue.length > 0)
109
+ return this.queue.shift();
110
+ return new Promise((resolve) => {
111
+ this.waiting = resolve;
112
+ });
113
+ }
114
+ close() {
115
+ this.closed = true;
116
+ if (this.waiting) {
117
+ this.waiting(null);
118
+ this.waiting = null;
119
+ }
120
+ }
121
+ }
@@ -0,0 +1,23 @@
1
+ import { ToolCall, ToolOutcome, HookDecision, PostHookResult, ToolContext } from '../core/types';
2
+ import { ProviderResponse } from '../infra/provider';
3
+ export interface Hooks {
4
+ preToolUse?: (call: ToolCall, ctx: ToolContext) => HookDecision | Promise<HookDecision>;
5
+ postToolUse?: (outcome: ToolOutcome, ctx: ToolContext) => PostHookResult | Promise<PostHookResult>;
6
+ preModel?: (request: any) => void | Promise<void>;
7
+ postModel?: (response: ProviderResponse) => void | Promise<void>;
8
+ messagesChanged?: (snapshot: any) => void | Promise<void>;
9
+ }
10
+ export interface RegisteredHook {
11
+ origin: 'agent' | 'toolTune';
12
+ names: Array<'preToolUse' | 'postToolUse' | 'preModel' | 'postModel'>;
13
+ }
14
+ export declare class HookManager {
15
+ private hooks;
16
+ register(hooks: Hooks, origin?: 'agent' | 'toolTune'): void;
17
+ getRegistered(): ReadonlyArray<RegisteredHook>;
18
+ runPreToolUse(call: ToolCall, ctx: ToolContext): Promise<HookDecision>;
19
+ runPostToolUse(outcome: ToolOutcome, ctx: ToolContext): Promise<ToolOutcome>;
20
+ runPreModel(request: any): Promise<void>;
21
+ runPostModel(response: ProviderResponse): Promise<void>;
22
+ runMessagesChanged(snapshot: any): Promise<void>;
23
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HookManager = void 0;
4
+ class HookManager {
5
+ constructor() {
6
+ this.hooks = [];
7
+ }
8
+ register(hooks, origin = 'agent') {
9
+ this.hooks.push({ hooks, origin });
10
+ }
11
+ getRegistered() {
12
+ return this.hooks.map(({ hooks, origin }) => ({
13
+ origin,
14
+ names: [
15
+ hooks.preToolUse && 'preToolUse',
16
+ hooks.postToolUse && 'postToolUse',
17
+ hooks.preModel && 'preModel',
18
+ hooks.postModel && 'postModel',
19
+ ].filter(Boolean),
20
+ }));
21
+ }
22
+ async runPreToolUse(call, ctx) {
23
+ for (const { hooks } of this.hooks) {
24
+ if (hooks.preToolUse) {
25
+ const result = await hooks.preToolUse(call, ctx);
26
+ if (result)
27
+ return result;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+ async runPostToolUse(outcome, ctx) {
33
+ let current = outcome;
34
+ for (const { hooks } of this.hooks) {
35
+ if (hooks.postToolUse) {
36
+ const result = await hooks.postToolUse(current, ctx);
37
+ if (result) {
38
+ if ('replace' in result) {
39
+ current = result.replace;
40
+ }
41
+ else if ('update' in result) {
42
+ current = { ...current, ...result.update };
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return current;
48
+ }
49
+ async runPreModel(request) {
50
+ for (const { hooks } of this.hooks) {
51
+ if (hooks.preModel) {
52
+ await hooks.preModel(request);
53
+ }
54
+ }
55
+ }
56
+ async runPostModel(response) {
57
+ for (const { hooks } of this.hooks) {
58
+ if (hooks.postModel) {
59
+ await hooks.postModel(response);
60
+ }
61
+ }
62
+ }
63
+ async runMessagesChanged(snapshot) {
64
+ for (const { hooks } of this.hooks) {
65
+ if (hooks.messagesChanged) {
66
+ await hooks.messagesChanged(snapshot);
67
+ }
68
+ }
69
+ }
70
+ }
71
+ exports.HookManager = HookManager;
@@ -0,0 +1,33 @@
1
+ import { Agent, AgentOptions } from '../core/agent';
2
+ import { Store } from '../infra/store';
3
+ import { AgentTemplate } from '../tools/task';
4
+ import { AgentStatus, SnapshotId } from '../core/types';
5
+ export interface AgentPoolOptions {
6
+ store: Store;
7
+ maxAgents?: number;
8
+ }
9
+ export declare class AgentPool {
10
+ private agents;
11
+ private store;
12
+ private maxAgents;
13
+ constructor(opts: AgentPoolOptions);
14
+ create(sessionId: string, templateOrOpts: AgentTemplate | AgentOptions, overrides?: Partial<AgentOptions>): Agent;
15
+ get(sessionId: string): Agent | undefined;
16
+ list(opts?: {
17
+ prefix?: string;
18
+ }): string[];
19
+ status(sessionId: string): Promise<AgentStatus | undefined>;
20
+ fork(sessionId: string, snapshotSel?: SnapshotId | {
21
+ at?: string;
22
+ }): Promise<Agent>;
23
+ resume(sessionId: string, opts: Omit<AgentOptions, 'sessionId' | 'store'> & {
24
+ autoRun?: boolean;
25
+ strategy?: 'crash' | 'manual';
26
+ }): Promise<Agent>;
27
+ resumeAll(configFactory: (sessionId: string) => Omit<AgentOptions, 'sessionId' | 'store'>, opts?: {
28
+ autoRun?: boolean;
29
+ strategy?: 'crash' | 'manual';
30
+ }): Promise<Agent[]>;
31
+ delete(sessionId: string): Promise<void>;
32
+ size(): number;
33
+ }
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentPool = void 0;
4
+ const agent_1 = require("../core/agent");
5
+ class AgentPool {
6
+ constructor(opts) {
7
+ this.agents = new Map();
8
+ this.store = opts.store;
9
+ this.maxAgents = opts.maxAgents || 50;
10
+ }
11
+ create(sessionId, templateOrOpts, overrides) {
12
+ if (this.agents.has(sessionId)) {
13
+ throw new Error(`Agent already exists: ${sessionId}`);
14
+ }
15
+ if (this.agents.size >= this.maxAgents) {
16
+ throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
17
+ }
18
+ const agent = new agent_1.Agent(templateOrOpts, overrides);
19
+ this.agents.set(sessionId, agent);
20
+ return agent;
21
+ }
22
+ get(sessionId) {
23
+ return this.agents.get(sessionId);
24
+ }
25
+ list(opts) {
26
+ const ids = Array.from(this.agents.keys());
27
+ return opts?.prefix ? ids.filter((id) => id.startsWith(opts.prefix)) : ids;
28
+ }
29
+ async status(sessionId) {
30
+ const agent = this.agents.get(sessionId);
31
+ return agent ? await agent.status() : undefined;
32
+ }
33
+ async fork(sessionId, snapshotSel) {
34
+ const agent = this.agents.get(sessionId);
35
+ if (!agent) {
36
+ throw new Error(`Agent not found: ${sessionId}`);
37
+ }
38
+ return agent.fork(snapshotSel);
39
+ }
40
+ async resume(sessionId, opts) {
41
+ // 1. Check if already in pool
42
+ if (this.agents.has(sessionId)) {
43
+ return this.agents.get(sessionId);
44
+ }
45
+ // 2. Check pool capacity
46
+ if (this.agents.size >= this.maxAgents) {
47
+ throw new Error(`Pool is full (max ${this.maxAgents} agents)`);
48
+ }
49
+ // 3. Verify session exists
50
+ const exists = await this.store.exists(sessionId);
51
+ if (!exists) {
52
+ throw new Error(`Session not found in store: ${sessionId}`);
53
+ }
54
+ // 4. Use Agent.resume() to restore
55
+ const agent = await agent_1.Agent.resume(sessionId, {
56
+ ...opts,
57
+ sessionId,
58
+ store: this.store,
59
+ });
60
+ // 5. Add to pool
61
+ this.agents.set(sessionId, agent);
62
+ return agent;
63
+ }
64
+ async resumeAll(configFactory, opts) {
65
+ const sessionIds = await this.store.list();
66
+ const resumed = [];
67
+ for (const sessionId of sessionIds) {
68
+ if (this.agents.size >= this.maxAgents)
69
+ break;
70
+ if (this.agents.has(sessionId))
71
+ continue;
72
+ try {
73
+ const config = configFactory(sessionId);
74
+ const agent = await this.resume(sessionId, { ...config, ...opts });
75
+ resumed.push(agent);
76
+ }
77
+ catch (error) {
78
+ console.error(`Failed to resume ${sessionId}:`, error);
79
+ }
80
+ }
81
+ return resumed;
82
+ }
83
+ async delete(sessionId) {
84
+ this.agents.delete(sessionId);
85
+ await this.store.delete(sessionId);
86
+ }
87
+ size() {
88
+ return this.agents.size;
89
+ }
90
+ }
91
+ exports.AgentPool = AgentPool;
@@ -0,0 +1,15 @@
1
+ import { AgentPool } from '../core/pool';
2
+ export interface RoomMember {
3
+ name: string;
4
+ sessionId: string;
5
+ }
6
+ export declare class Room {
7
+ private pool;
8
+ private members;
9
+ constructor(pool: AgentPool);
10
+ join(name: string, sessionId: string): void;
11
+ leave(name: string): void;
12
+ say(from: string, text: string): Promise<void>;
13
+ getMembers(): RoomMember[];
14
+ private extractMentions;
15
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Room = void 0;
4
+ class Room {
5
+ constructor(pool) {
6
+ this.pool = pool;
7
+ this.members = new Map();
8
+ }
9
+ join(name, sessionId) {
10
+ if (this.members.has(name)) {
11
+ throw new Error(`Member already exists: ${name}`);
12
+ }
13
+ this.members.set(name, sessionId);
14
+ }
15
+ leave(name) {
16
+ this.members.delete(name);
17
+ }
18
+ async say(from, text) {
19
+ const mentions = this.extractMentions(text);
20
+ if (mentions.length > 0) {
21
+ // Directed message
22
+ for (const mention of mentions) {
23
+ const sessionId = this.members.get(mention);
24
+ if (sessionId) {
25
+ const agent = this.pool.get(sessionId);
26
+ if (agent) {
27
+ await agent.send(`[from:${from}] ${text}`);
28
+ }
29
+ }
30
+ }
31
+ }
32
+ else {
33
+ // Broadcast to all except sender
34
+ for (const [name, sessionId] of this.members) {
35
+ if (name !== from) {
36
+ const agent = this.pool.get(sessionId);
37
+ if (agent) {
38
+ await agent.send(`[from:${from}] ${text}`);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ getMembers() {
45
+ return Array.from(this.members.entries()).map(([name, sessionId]) => ({ name, sessionId }));
46
+ }
47
+ extractMentions(text) {
48
+ const regex = /@(\w+)/g;
49
+ const mentions = [];
50
+ let match;
51
+ while ((match = regex.exec(text)) !== null) {
52
+ mentions.push(match[1]);
53
+ }
54
+ return mentions;
55
+ }
56
+ }
57
+ exports.Room = Room;
@@ -0,0 +1,26 @@
1
+ type TimeInterval = string;
2
+ type ScheduleCallback = (ctx?: any) => void | Promise<void>;
3
+ export declare class Scheduler {
4
+ private tasks;
5
+ private stepCounters;
6
+ private timers;
7
+ every(interval: TimeInterval, callback: ScheduleCallback): this;
8
+ everySteps(steps: number, callback: ScheduleCallback, targetId?: string): this;
9
+ daily(time: string, callback: ScheduleCallback): this;
10
+ weekly(dayTime: string, callback: ScheduleCallback): this;
11
+ notifyStep(targetId?: string): void;
12
+ stop(): void;
13
+ private parseInterval;
14
+ private scheduleDailyTask;
15
+ private scheduleWeeklyTask;
16
+ }
17
+ export declare class AgentSchedulerHandle {
18
+ private scheduler;
19
+ private agentId?;
20
+ constructor(scheduler: Scheduler, agentId?: string | undefined);
21
+ every(interval: TimeInterval, callback: ScheduleCallback): this;
22
+ everySteps(steps: number, callback: ScheduleCallback): this;
23
+ daily(time: string, callback: ScheduleCallback): this;
24
+ weekly(dayTime: string, callback: ScheduleCallback): this;
25
+ }
26
+ export {};
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentSchedulerHandle = exports.Scheduler = void 0;
4
+ class Scheduler {
5
+ constructor() {
6
+ this.tasks = new Map();
7
+ this.stepCounters = new Map();
8
+ this.timers = [];
9
+ }
10
+ every(interval, callback) {
11
+ const ms = this.parseInterval(interval);
12
+ const id = `time-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
13
+ const task = {
14
+ id,
15
+ type: 'time',
16
+ spec: interval,
17
+ callback,
18
+ enabled: true,
19
+ };
20
+ this.tasks.set(id, task);
21
+ const timer = setInterval(() => {
22
+ if (task.enabled) {
23
+ task.callback({ count: 0, type: 'time', id });
24
+ task.lastRun = Date.now();
25
+ }
26
+ }, ms);
27
+ this.timers.push(timer);
28
+ return this;
29
+ }
30
+ everySteps(steps, callback, targetId) {
31
+ const id = targetId || `step-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
32
+ const task = {
33
+ id,
34
+ type: 'step',
35
+ spec: steps,
36
+ callback,
37
+ enabled: true,
38
+ };
39
+ this.tasks.set(id, task);
40
+ this.stepCounters.set(id, 0);
41
+ return this;
42
+ }
43
+ daily(time, callback) {
44
+ const id = `daily-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
45
+ const task = {
46
+ id,
47
+ type: 'daily',
48
+ spec: time,
49
+ callback,
50
+ enabled: true,
51
+ };
52
+ this.tasks.set(id, task);
53
+ this.scheduleDailyTask(task);
54
+ return this;
55
+ }
56
+ weekly(dayTime, callback) {
57
+ const id = `weekly-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
58
+ const task = {
59
+ id,
60
+ type: 'weekly',
61
+ spec: dayTime,
62
+ callback,
63
+ enabled: true,
64
+ };
65
+ this.tasks.set(id, task);
66
+ this.scheduleWeeklyTask(task);
67
+ return this;
68
+ }
69
+ notifyStep(targetId) {
70
+ for (const [id, task] of this.tasks) {
71
+ if (task.type === 'step' && (!targetId || id === targetId)) {
72
+ const count = (this.stepCounters.get(id) || 0) + 1;
73
+ this.stepCounters.set(id, count);
74
+ if (count >= task.spec) {
75
+ task.callback({ count, type: 'step', id });
76
+ this.stepCounters.set(id, 0);
77
+ task.lastRun = Date.now();
78
+ }
79
+ }
80
+ }
81
+ }
82
+ stop() {
83
+ for (const timer of this.timers) {
84
+ clearInterval(timer);
85
+ }
86
+ this.timers = [];
87
+ this.tasks.clear();
88
+ this.stepCounters.clear();
89
+ }
90
+ parseInterval(interval) {
91
+ const match = interval.match(/^(\d+)(s|m|h|d)$/);
92
+ if (!match)
93
+ throw new Error(`Invalid interval: ${interval}`);
94
+ const value = parseInt(match[1], 10);
95
+ const unit = match[2];
96
+ switch (unit) {
97
+ case 's':
98
+ return value * 1000;
99
+ case 'm':
100
+ return value * 60 * 1000;
101
+ case 'h':
102
+ return value * 60 * 60 * 1000;
103
+ case 'd':
104
+ return value * 24 * 60 * 60 * 1000;
105
+ default:
106
+ throw new Error(`Unknown unit: ${unit}`);
107
+ }
108
+ }
109
+ scheduleDailyTask(task) {
110
+ const [hours, minutes] = task.spec.split(':').map(Number);
111
+ const now = new Date();
112
+ const target = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, minutes, 0);
113
+ if (target.getTime() <= now.getTime()) {
114
+ target.setDate(target.getDate() + 1);
115
+ }
116
+ const delay = target.getTime() - now.getTime();
117
+ const timeout = setTimeout(() => {
118
+ if (task.enabled) {
119
+ task.callback({ time: task.spec, type: 'daily', id: task.id });
120
+ task.lastRun = Date.now();
121
+ }
122
+ this.scheduleDailyTask(task);
123
+ }, delay);
124
+ this.timers.push(timeout);
125
+ }
126
+ scheduleWeeklyTask(task) {
127
+ const [day, time] = task.spec.split(' ');
128
+ const [hours, minutes] = time.split(':').map(Number);
129
+ const dayMap = {
130
+ Sun: 0,
131
+ Mon: 1,
132
+ Tue: 2,
133
+ Wed: 3,
134
+ Thu: 4,
135
+ Fri: 5,
136
+ Sat: 6,
137
+ };
138
+ const targetDay = dayMap[day];
139
+ if (targetDay === undefined)
140
+ throw new Error(`Invalid day: ${day}`);
141
+ const now = new Date();
142
+ const target = new Date(now);
143
+ target.setHours(hours, minutes, 0, 0);
144
+ const currentDay = now.getDay();
145
+ let daysUntilTarget = targetDay - currentDay;
146
+ if (daysUntilTarget < 0 || (daysUntilTarget === 0 && target.getTime() <= now.getTime())) {
147
+ daysUntilTarget += 7;
148
+ }
149
+ target.setDate(target.getDate() + daysUntilTarget);
150
+ const delay = target.getTime() - now.getTime();
151
+ const timeout = setTimeout(() => {
152
+ if (task.enabled) {
153
+ task.callback({ time: task.spec, type: 'weekly', id: task.id });
154
+ task.lastRun = Date.now();
155
+ }
156
+ this.scheduleWeeklyTask(task);
157
+ }, delay);
158
+ this.timers.push(timeout);
159
+ }
160
+ }
161
+ exports.Scheduler = Scheduler;
162
+ class AgentSchedulerHandle {
163
+ constructor(scheduler, agentId) {
164
+ this.scheduler = scheduler;
165
+ this.agentId = agentId;
166
+ }
167
+ every(interval, callback) {
168
+ this.scheduler.every(interval, callback);
169
+ return this;
170
+ }
171
+ everySteps(steps, callback) {
172
+ this.scheduler.everySteps(steps, callback, this.agentId);
173
+ return this;
174
+ }
175
+ daily(time, callback) {
176
+ this.scheduler.daily(time, callback);
177
+ return this;
178
+ }
179
+ weekly(dayTime, callback) {
180
+ this.scheduler.weekly(dayTime, callback);
181
+ return this;
182
+ }
183
+ }
184
+ exports.AgentSchedulerHandle = AgentSchedulerHandle;