@gracefultools/astrid-sdk 0.4.2 → 0.6.1

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,177 @@
1
+ "use strict";
2
+ /**
3
+ * Repository Manager
4
+ *
5
+ * Handles cloning and updating GitHub repositories for AI agents to work on.
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.repoManager = void 0;
12
+ const child_process_1 = require("child_process");
13
+ const fs_1 = require("fs");
14
+ const path_1 = __importDefault(require("path"));
15
+ const REPOS_DIR = process.env.REPOS_DIR || './repos';
16
+ class RepoManager {
17
+ reposDir;
18
+ constructor() {
19
+ this.reposDir = REPOS_DIR;
20
+ // Ensure repos directory exists
21
+ if (!(0, fs_1.existsSync)(this.reposDir)) {
22
+ (0, fs_1.mkdirSync)(this.reposDir, { recursive: true });
23
+ }
24
+ }
25
+ /**
26
+ * Get or clone a repository
27
+ */
28
+ async getRepo(repoId) {
29
+ if (!repoId) {
30
+ return null;
31
+ }
32
+ // Parse repo ID (e.g., "Graceful-Tools/astrid-res-www")
33
+ const [owner, repo] = repoId.split('/');
34
+ if (!owner || !repo) {
35
+ console.error(`Invalid repo ID: ${repoId}`);
36
+ return null;
37
+ }
38
+ const repoPath = path_1.default.join(this.reposDir, owner, repo);
39
+ const repoUrl = this.buildRepoUrl(owner, repo);
40
+ // Check if already cloned
41
+ if ((0, fs_1.existsSync)(path_1.default.join(repoPath, '.git'))) {
42
+ console.log(`📂 Repository exists: ${repoPath}`);
43
+ // Pull latest changes
44
+ await this.pullLatest(repoPath);
45
+ return {
46
+ path: repoPath,
47
+ url: repoUrl,
48
+ branch: await this.getCurrentBranch(repoPath)
49
+ };
50
+ }
51
+ // Clone the repository
52
+ console.log(`📥 Cloning repository: ${repoId}`);
53
+ const success = await this.cloneRepo(repoUrl, repoPath);
54
+ if (!success) {
55
+ return null;
56
+ }
57
+ return {
58
+ path: repoPath,
59
+ url: repoUrl,
60
+ branch: await this.getCurrentBranch(repoPath)
61
+ };
62
+ }
63
+ /**
64
+ * Build repository URL (supports GitHub token for private repos)
65
+ */
66
+ buildRepoUrl(owner, repo) {
67
+ const token = process.env.GITHUB_TOKEN;
68
+ if (token) {
69
+ return `https://${token}@github.com/${owner}/${repo}.git`;
70
+ }
71
+ return `https://github.com/${owner}/${repo}.git`;
72
+ }
73
+ /**
74
+ * Clone a repository
75
+ */
76
+ async cloneRepo(url, targetPath) {
77
+ return new Promise((resolve) => {
78
+ // Ensure parent directory exists
79
+ const parentDir = path_1.default.dirname(targetPath);
80
+ if (!(0, fs_1.existsSync)(parentDir)) {
81
+ (0, fs_1.mkdirSync)(parentDir, { recursive: true });
82
+ }
83
+ // Sanitize URL for logging (hide token)
84
+ const safeUrl = url.replace(/https:\/\/[^@]+@/, 'https://***@');
85
+ console.log(`🔄 Cloning ${safeUrl} to ${targetPath}`);
86
+ const proc = (0, child_process_1.spawn)('git', ['clone', '--depth', '100', url, targetPath], {
87
+ timeout: 120000 // 2 minute timeout for clone
88
+ });
89
+ proc.stdout.on('data', (data) => {
90
+ console.log(`git: ${data.toString().trim()}`);
91
+ });
92
+ proc.stderr.on('data', (data) => {
93
+ // Git outputs progress to stderr
94
+ console.log(`git: ${data.toString().trim()}`);
95
+ });
96
+ proc.on('close', (code) => {
97
+ if (code === 0) {
98
+ console.log(`✅ Repository cloned successfully`);
99
+ resolve(true);
100
+ }
101
+ else {
102
+ console.error(`❌ Failed to clone repository (exit code ${code})`);
103
+ resolve(false);
104
+ }
105
+ });
106
+ proc.on('error', (error) => {
107
+ console.error(`❌ Git clone error:`, error);
108
+ resolve(false);
109
+ });
110
+ });
111
+ }
112
+ /**
113
+ * Pull latest changes
114
+ */
115
+ async pullLatest(repoPath) {
116
+ return new Promise((resolve) => {
117
+ console.log(`🔄 Pulling latest changes in ${repoPath}`);
118
+ const proc = (0, child_process_1.spawn)('git', ['pull', '--ff-only'], {
119
+ cwd: repoPath,
120
+ timeout: 60000
121
+ });
122
+ proc.on('close', (code) => {
123
+ if (code === 0) {
124
+ console.log(`✅ Repository updated`);
125
+ resolve(true);
126
+ }
127
+ else {
128
+ console.log(`⚠️ Pull failed (code ${code}), continuing with existing code`);
129
+ resolve(true); // Still allow work to continue
130
+ }
131
+ });
132
+ proc.on('error', () => {
133
+ console.log(`⚠️ Pull error, continuing with existing code`);
134
+ resolve(true);
135
+ });
136
+ });
137
+ }
138
+ /**
139
+ * Get current branch name
140
+ */
141
+ async getCurrentBranch(repoPath) {
142
+ try {
143
+ const branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
144
+ cwd: repoPath,
145
+ encoding: 'utf-8'
146
+ }).trim();
147
+ return branch;
148
+ }
149
+ catch {
150
+ return 'main';
151
+ }
152
+ }
153
+ /**
154
+ * Create a new branch for the task
155
+ */
156
+ async createTaskBranch(repoPath, taskId) {
157
+ const branchName = `astrid/${taskId.slice(0, 8)}`;
158
+ try {
159
+ // Check if branch already exists
160
+ (0, child_process_1.execSync)(`git rev-parse --verify ${branchName}`, {
161
+ cwd: repoPath,
162
+ stdio: 'pipe'
163
+ });
164
+ // Branch exists, checkout
165
+ (0, child_process_1.execSync)(`git checkout ${branchName}`, { cwd: repoPath });
166
+ console.log(`📂 Checked out existing branch: ${branchName}`);
167
+ }
168
+ catch {
169
+ // Branch doesn't exist, create it
170
+ (0, child_process_1.execSync)(`git checkout -b ${branchName}`, { cwd: repoPath });
171
+ console.log(`🌿 Created new branch: ${branchName}`);
172
+ }
173
+ return branchName;
174
+ }
175
+ }
176
+ exports.repoManager = new RepoManager();
177
+ //# sourceMappingURL=repo-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-manager.js","sourceRoot":"","sources":["../../src/server/repo-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Session Manager
3
+ *
4
+ * Maps Astrid tasks to AI provider sessions with persistence.
5
+ * Enables session resumption for Claude Code via --resume flag.
6
+ */
7
+ export type AIProvider = 'claude' | 'openai' | 'gemini' | 'unknown';
8
+ export interface Session {
9
+ id: string;
10
+ taskId: string;
11
+ title: string;
12
+ description: string;
13
+ projectPath?: string;
14
+ /** AI provider used for this session */
15
+ provider?: AIProvider;
16
+ /** Provider-specific session ID (e.g., Claude's session ID for --resume) */
17
+ claudeSessionId?: string;
18
+ status: 'pending' | 'running' | 'waiting_input' | 'completed' | 'error' | 'interrupted';
19
+ createdAt: string;
20
+ updatedAt: string;
21
+ messageCount: number;
22
+ lastActivity?: string;
23
+ metadata?: Record<string, unknown>;
24
+ }
25
+ export interface CreateSessionOptions {
26
+ taskId: string;
27
+ title: string;
28
+ description: string;
29
+ projectPath?: string;
30
+ /** AI provider for this session */
31
+ provider?: AIProvider;
32
+ metadata?: Record<string, unknown>;
33
+ }
34
+ export declare class SessionManager {
35
+ private storagePath;
36
+ private sessions;
37
+ private loaded;
38
+ constructor(storagePath?: string);
39
+ /**
40
+ * Load sessions from disk
41
+ */
42
+ load(): Promise<void>;
43
+ /**
44
+ * Save sessions to disk
45
+ */
46
+ save(): Promise<void>;
47
+ /**
48
+ * Create a new session for a task
49
+ */
50
+ createSession(options: CreateSessionOptions): Promise<Session>;
51
+ /**
52
+ * Get session by task ID
53
+ */
54
+ getByTaskId(taskId: string): Promise<Session | undefined>;
55
+ /**
56
+ * Get session by session ID
57
+ */
58
+ getById(sessionId: string): Promise<Session | undefined>;
59
+ /**
60
+ * Update a session
61
+ */
62
+ updateSession(taskId: string, updates: Partial<Omit<Session, 'id' | 'taskId' | 'createdAt'>>): Promise<Session | null>;
63
+ /**
64
+ * Set Claude session ID after first response
65
+ */
66
+ setClaudeSessionId(taskId: string, claudeSessionId: string): Promise<void>;
67
+ /**
68
+ * Increment message count
69
+ */
70
+ incrementMessageCount(taskId: string): Promise<void>;
71
+ /**
72
+ * Delete a session
73
+ */
74
+ deleteSession(taskId: string): Promise<boolean>;
75
+ /**
76
+ * Get all sessions
77
+ */
78
+ getAllSessions(): Promise<Session[]>;
79
+ /**
80
+ * Get active sessions (running or waiting_input)
81
+ */
82
+ getActiveSessions(): Promise<Session[]>;
83
+ /**
84
+ * Cleanup expired sessions (older than maxAge)
85
+ */
86
+ cleanupExpired(maxAgeMs?: number): Promise<number>;
87
+ /**
88
+ * Mark interrupted sessions on startup
89
+ */
90
+ recoverSessions(): Promise<Session[]>;
91
+ }
92
+ export declare const sessionManager: SessionManager;
93
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/server/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEnE,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,UAAU,CAAA;IACrB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,WAAW,GAAG,OAAO,GAAG,aAAa,CAAA;IACvF,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,UAAU,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,MAAM,CAAQ;gBAEV,WAAW,CAAC,EAAE,MAAM;IAOhC;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IA0BpE;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAK/D;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAU9D;;OAEG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,QAAQ,GAAG,WAAW,CAAC,CAAC,GAC7D,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAc1B;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAShF;;OAEG;IACG,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1D;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrD;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAK1C;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAO7C;;OAEG;IACG,cAAc,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB7E;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;CAoB5C;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAA"}
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ /**
3
+ * Session Manager
4
+ *
5
+ * Maps Astrid tasks to AI provider sessions with persistence.
6
+ * Enables session resumption for Claude Code via --resume flag.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.sessionManager = exports.SessionManager = void 0;
13
+ const promises_1 = __importDefault(require("fs/promises"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const crypto_1 = __importDefault(require("crypto"));
16
+ class SessionManager {
17
+ storagePath;
18
+ sessions = new Map();
19
+ loaded = false;
20
+ constructor(storagePath) {
21
+ // Default to data/sessions in current directory or /app/persistent for Docker
22
+ const defaultDir = process.env.SESSIONS_DIR ||
23
+ (process.env.NODE_ENV === 'production' ? '/app/persistent/sessions' : './data/sessions');
24
+ this.storagePath = storagePath || process.env.SESSION_MAP_PATH || `${defaultDir}/sessions.json`;
25
+ }
26
+ /**
27
+ * Load sessions from disk
28
+ */
29
+ async load() {
30
+ if (this.loaded)
31
+ return;
32
+ try {
33
+ const dir = path_1.default.dirname(this.storagePath);
34
+ await promises_1.default.mkdir(dir, { recursive: true });
35
+ const data = await promises_1.default.readFile(this.storagePath, 'utf-8');
36
+ const parsed = JSON.parse(data);
37
+ this.sessions = new Map(Object.entries(parsed));
38
+ this.loaded = true;
39
+ console.log(`📂 Loaded ${this.sessions.size} sessions from ${this.storagePath}`);
40
+ }
41
+ catch (error) {
42
+ if (error.code === 'ENOENT') {
43
+ this.sessions = new Map();
44
+ this.loaded = true;
45
+ console.log(`📂 No existing sessions file, starting fresh`);
46
+ }
47
+ else {
48
+ throw error;
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Save sessions to disk
54
+ */
55
+ async save() {
56
+ try {
57
+ const data = Object.fromEntries(this.sessions);
58
+ const dir = path_1.default.dirname(this.storagePath);
59
+ await promises_1.default.mkdir(dir, { recursive: true });
60
+ await promises_1.default.writeFile(this.storagePath, JSON.stringify(data, null, 2));
61
+ }
62
+ catch (error) {
63
+ // Log but don't crash - sessions will be in-memory only
64
+ console.error(`⚠️ Failed to persist sessions: ${error.message}`);
65
+ }
66
+ }
67
+ /**
68
+ * Create a new session for a task
69
+ */
70
+ async createSession(options) {
71
+ await this.load();
72
+ const session = {
73
+ id: crypto_1.default.randomUUID(),
74
+ taskId: options.taskId,
75
+ title: options.title,
76
+ description: options.description,
77
+ projectPath: options.projectPath,
78
+ provider: options.provider || 'claude',
79
+ claudeSessionId: undefined,
80
+ status: 'pending',
81
+ createdAt: new Date().toISOString(),
82
+ updatedAt: new Date().toISOString(),
83
+ messageCount: 0,
84
+ lastActivity: undefined,
85
+ metadata: options.metadata
86
+ };
87
+ this.sessions.set(options.taskId, session);
88
+ await this.save();
89
+ console.log(`📝 Created session ${session.id} for task ${options.taskId} (provider: ${session.provider})`);
90
+ return session;
91
+ }
92
+ /**
93
+ * Get session by task ID
94
+ */
95
+ async getByTaskId(taskId) {
96
+ await this.load();
97
+ return this.sessions.get(taskId);
98
+ }
99
+ /**
100
+ * Get session by session ID
101
+ */
102
+ async getById(sessionId) {
103
+ await this.load();
104
+ for (const session of this.sessions.values()) {
105
+ if (session.id === sessionId) {
106
+ return session;
107
+ }
108
+ }
109
+ return undefined;
110
+ }
111
+ /**
112
+ * Update a session
113
+ */
114
+ async updateSession(taskId, updates) {
115
+ await this.load();
116
+ const session = this.sessions.get(taskId);
117
+ if (!session)
118
+ return null;
119
+ Object.assign(session, updates, {
120
+ updatedAt: new Date().toISOString()
121
+ });
122
+ await this.save();
123
+ return session;
124
+ }
125
+ /**
126
+ * Set Claude session ID after first response
127
+ */
128
+ async setClaudeSessionId(taskId, claudeSessionId) {
129
+ await this.updateSession(taskId, {
130
+ claudeSessionId,
131
+ status: 'running',
132
+ lastActivity: new Date().toISOString()
133
+ });
134
+ console.log(`🔗 Linked Claude session ${claudeSessionId} to task ${taskId}`);
135
+ }
136
+ /**
137
+ * Increment message count
138
+ */
139
+ async incrementMessageCount(taskId) {
140
+ const session = await this.getByTaskId(taskId);
141
+ if (session) {
142
+ await this.updateSession(taskId, {
143
+ messageCount: session.messageCount + 1,
144
+ lastActivity: new Date().toISOString()
145
+ });
146
+ }
147
+ }
148
+ /**
149
+ * Delete a session
150
+ */
151
+ async deleteSession(taskId) {
152
+ await this.load();
153
+ if (!this.sessions.has(taskId))
154
+ return false;
155
+ this.sessions.delete(taskId);
156
+ await this.save();
157
+ console.log(`🗑️ Deleted session for task ${taskId}`);
158
+ return true;
159
+ }
160
+ /**
161
+ * Get all sessions
162
+ */
163
+ async getAllSessions() {
164
+ await this.load();
165
+ return Array.from(this.sessions.values());
166
+ }
167
+ /**
168
+ * Get active sessions (running or waiting_input)
169
+ */
170
+ async getActiveSessions() {
171
+ await this.load();
172
+ return Array.from(this.sessions.values()).filter(s => s.status === 'running' || s.status === 'waiting_input');
173
+ }
174
+ /**
175
+ * Cleanup expired sessions (older than maxAge)
176
+ */
177
+ async cleanupExpired(maxAgeMs = 24 * 60 * 60 * 1000) {
178
+ await this.load();
179
+ const now = Date.now();
180
+ let cleaned = 0;
181
+ for (const [taskId, session] of this.sessions) {
182
+ const age = now - new Date(session.updatedAt).getTime();
183
+ if (age > maxAgeMs && session.status !== 'running') {
184
+ this.sessions.delete(taskId);
185
+ cleaned++;
186
+ }
187
+ }
188
+ if (cleaned > 0) {
189
+ await this.save();
190
+ console.log(`🧹 Cleaned up ${cleaned} expired sessions`);
191
+ }
192
+ return cleaned;
193
+ }
194
+ /**
195
+ * Mark interrupted sessions on startup
196
+ */
197
+ async recoverSessions() {
198
+ await this.load();
199
+ const interrupted = [];
200
+ for (const session of this.sessions.values()) {
201
+ if (session.status === 'running') {
202
+ session.status = 'interrupted';
203
+ session.updatedAt = new Date().toISOString();
204
+ interrupted.push(session);
205
+ }
206
+ }
207
+ if (interrupted.length > 0) {
208
+ await this.save();
209
+ console.log(`⚠️ Marked ${interrupted.length} sessions as interrupted`);
210
+ }
211
+ return interrupted;
212
+ }
213
+ }
214
+ exports.SessionManager = SessionManager;
215
+ // Export singleton instance
216
+ exports.sessionManager = new SessionManager();
217
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/server/session-manager.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,2DAA4B;AAC5B,gDAAuB;AACvB,oDAA2B;AAgC3B,MAAa,cAAc;IACjB,WAAW,CAAQ;IACnB,QAAQ,GAAyB,IAAI,GAAG,EAAE,CAAA;IAC1C,MAAM,GAAG,KAAK,CAAA;IAEtB,YAAY,WAAoB;QAC9B,8EAA8E;QAC9E,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY;YACzC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAA;QAC1F,IAAI,CAAC,WAAW,GAAG,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,UAAU,gBAAgB,CAAA;IACjG,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QAEvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YAC1C,MAAM,kBAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YAExC,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;YACzD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4B,CAAA;YAC1D,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;YAC/C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;YAClB,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,QAAQ,CAAC,IAAI,kBAAkB,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QAClF,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACvD,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAE,CAAA;gBACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;gBAClB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAA;YAC7D,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAA;YACb,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC9C,MAAM,GAAG,GAAG,cAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YAC1C,MAAM,kBAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;YACxC,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wDAAwD;YACxD,OAAO,CAAC,KAAK,CAAC,kCAAmC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAA6B;QAC/C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,MAAM,OAAO,GAAY;YACvB,EAAE,EAAE,gBAAM,CAAC,UAAU,EAAE;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ;YACtC,eAAe,EAAE,SAAS;YAC1B,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,YAAY,EAAE,CAAC;YACf,YAAY,EAAE,SAAS;YACvB,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAA;QAED,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,OAAO,CAAC,GAAG,CAAC,sBAAsB,OAAO,CAAC,EAAE,aAAa,OAAO,CAAC,MAAM,eAAe,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;QAC1G,OAAO,OAAO,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,MAAc;QAC9B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,SAAiB;QAC7B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;gBAC7B,OAAO,OAAO,CAAA;YAChB,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CACjB,MAAc,EACd,OAA8D;QAE9D,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzC,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAA;QAEzB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE;YAC9B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC,CAAA;QAEF,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,OAAO,OAAO,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,MAAc,EAAE,eAAuB;QAC9D,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;YAC/B,eAAe;YACf,MAAM,EAAE,SAAS;YACjB,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAC,CAAA;QACF,OAAO,CAAC,GAAG,CAAC,4BAA4B,eAAe,YAAY,MAAM,EAAE,CAAC,CAAA;IAC9E,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB,CAAC,MAAc;QACxC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE;gBAC/B,YAAY,EAAE,OAAO,CAAC,YAAY,GAAG,CAAC;gBACtC,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACvC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,MAAc;QAChC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QAE5C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAC5B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,OAAO,CAAC,GAAG,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAA;QACrD,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe,CAC5D,CAAA;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,WAAmB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;QACzD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,IAAI,OAAO,GAAG,CAAC,CAAA;QAEf,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9C,MAAM,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAA;YACvD,IAAI,GAAG,GAAG,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACnD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBAC5B,OAAO,EAAE,CAAA;YACX,CAAC;QACH,CAAC;QAED,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;YACjB,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,mBAAmB,CAAC,CAAA;QAC1D,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAEjB,MAAM,WAAW,GAAc,EAAE,CAAA;QAEjC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,OAAO,CAAC,MAAM,GAAG,aAAa,CAAA;gBAC9B,OAAO,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;gBAC5C,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC3B,CAAC;QACH,CAAC;QAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;YACjB,OAAO,CAAC,GAAG,CAAC,aAAa,WAAW,CAAC,MAAM,0BAA0B,CAAC,CAAA;QACxE,CAAC;QAED,OAAO,WAAW,CAAA;IACpB,CAAC;CACF;AApOD,wCAoOC;AAED,4BAA4B;AACf,QAAA,cAAc,GAAG,IAAI,cAAc,EAAE,CAAA"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Webhook Signature Utilities
3
+ *
4
+ * HMAC-SHA256 signature verification for secure webhook communication
5
+ * from Astrid to the SDK server.
6
+ */
7
+ /**
8
+ * Generate HMAC-SHA256 signature for a webhook payload
9
+ */
10
+ export declare function generateWebhookSignature(payload: string, secret: string, timestamp: string): string;
11
+ /**
12
+ * Generate all headers needed for a signed callback request to Astrid
13
+ */
14
+ export declare function generateCallbackHeaders(payload: string, secret: string, event: string): Record<string, string>;
15
+ export interface WebhookVerificationResult {
16
+ valid: boolean;
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Verify a webhook signature from Astrid
21
+ */
22
+ export declare function verifyWebhookSignature(payload: string, signature: string, secret: string, timestamp: string, maxAge?: number): WebhookVerificationResult;
23
+ //# sourceMappingURL=webhook-signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.d.ts","sourceRoot":"","sources":["../../src/server/webhook-signature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWxB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,OAAO,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAe,GACtB,yBAAyB,CAoC3B"}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Webhook Signature Utilities
4
+ *
5
+ * HMAC-SHA256 signature verification for secure webhook communication
6
+ * from Astrid to the SDK server.
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.generateWebhookSignature = generateWebhookSignature;
13
+ exports.generateCallbackHeaders = generateCallbackHeaders;
14
+ exports.verifyWebhookSignature = verifyWebhookSignature;
15
+ const crypto_1 = __importDefault(require("crypto"));
16
+ /**
17
+ * Generate HMAC-SHA256 signature for a webhook payload
18
+ */
19
+ function generateWebhookSignature(payload, secret, timestamp) {
20
+ const signedPayload = `${timestamp}.${payload}`;
21
+ return crypto_1.default
22
+ .createHmac('sha256', secret)
23
+ .update(signedPayload, 'utf8')
24
+ .digest('hex');
25
+ }
26
+ /**
27
+ * Generate all headers needed for a signed callback request to Astrid
28
+ */
29
+ function generateCallbackHeaders(payload, secret, event) {
30
+ const timestamp = Date.now().toString();
31
+ const signature = generateWebhookSignature(payload, secret, timestamp);
32
+ return {
33
+ 'Content-Type': 'application/json',
34
+ 'X-Astrid-Signature': `sha256=${signature}`,
35
+ 'X-Astrid-Timestamp': timestamp,
36
+ 'X-Astrid-Event': event,
37
+ 'User-Agent': 'Astrid-SDK/1.0'
38
+ };
39
+ }
40
+ /**
41
+ * Verify a webhook signature from Astrid
42
+ */
43
+ function verifyWebhookSignature(payload, signature, secret, timestamp, maxAge = 300000 // 5 minutes
44
+ ) {
45
+ if (!payload || !signature || !secret || !timestamp) {
46
+ return { valid: false, error: 'Missing required parameters' };
47
+ }
48
+ const now = Date.now();
49
+ const ts = parseInt(timestamp, 10);
50
+ if (isNaN(ts)) {
51
+ return { valid: false, error: 'Invalid timestamp format' };
52
+ }
53
+ if (now - ts > maxAge) {
54
+ return { valid: false, error: 'Timestamp expired' };
55
+ }
56
+ if (ts - now > 60000) {
57
+ return { valid: false, error: 'Timestamp too far in future' };
58
+ }
59
+ const expected = generateWebhookSignature(payload, secret, timestamp);
60
+ const actual = signature.replace(/^sha256=/, '');
61
+ try {
62
+ const expectedBuffer = Buffer.from(expected, 'hex');
63
+ const actualBuffer = Buffer.from(actual, 'hex');
64
+ if (expectedBuffer.length !== actualBuffer.length) {
65
+ return { valid: false, error: 'Signature length mismatch' };
66
+ }
67
+ const valid = crypto_1.default.timingSafeEqual(expectedBuffer, actualBuffer);
68
+ return { valid };
69
+ }
70
+ catch {
71
+ return { valid: false, error: 'Signature mismatch' };
72
+ }
73
+ }
74
+ //# sourceMappingURL=webhook-signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.js","sourceRoot":"","sources":["../../src/server/webhook-signature.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AAOH,4DAUC;AAKD,0DAeC;AAUD,wDA0CC;AAvFD,oDAA2B;AAE3B;;GAEG;AACH,SAAgB,wBAAwB,CACtC,OAAe,EACf,MAAc,EACd,SAAiB;IAEjB,MAAM,aAAa,GAAG,GAAG,SAAS,IAAI,OAAO,EAAE,CAAA;IAC/C,OAAO,gBAAM;SACV,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC5B,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC;SAC7B,MAAM,CAAC,KAAK,CAAC,CAAA;AAClB,CAAC;AAED;;GAEG;AACH,SAAgB,uBAAuB,CACrC,OAAe,EACf,MAAc,EACd,KAAa;IAEb,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAA;IACvC,MAAM,SAAS,GAAG,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IAEtE,OAAO;QACL,cAAc,EAAE,kBAAkB;QAClC,oBAAoB,EAAE,UAAU,SAAS,EAAE;QAC3C,oBAAoB,EAAE,SAAS;QAC/B,gBAAgB,EAAE,KAAK;QACvB,YAAY,EAAE,gBAAgB;KAC/B,CAAA;AACH,CAAC;AAOD;;GAEG;AACH,SAAgB,sBAAsB,CACpC,OAAe,EACf,SAAiB,EACjB,MAAc,EACd,SAAiB,EACjB,SAAiB,MAAM,CAAC,YAAY;;IAEpC,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACpD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;IAC/D,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACtB,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAElC,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACd,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAA;IAC5D,CAAC;IAED,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;QACtB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAA;IACrD,CAAC;IAED,IAAI,EAAE,GAAG,GAAG,GAAG,KAAK,EAAE,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;IAC/D,CAAC;IAED,MAAM,QAAQ,GAAG,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACrE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAEhD,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QACnD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAE/C,IAAI,cAAc,CAAC,MAAM,KAAK,YAAY,CAAC,MAAM,EAAE,CAAC;YAClD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAA;QAC7D,CAAC;QAED,MAAM,KAAK,GAAG,gBAAM,CAAC,eAAe,CAAC,cAAc,EAAE,YAAY,CAAC,CAAA;QAClE,OAAO,EAAE,KAAK,EAAE,CAAA;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;IACtD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gracefultools/astrid-sdk",
3
- "version": "0.4.2",
3
+ "version": "0.6.1",
4
4
  "description": "AI agent SDK for automated coding tasks with Claude, OpenAI, and Gemini",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -53,17 +53,22 @@
53
53
  "glob": "^10.3.10"
54
54
  },
55
55
  "peerDependencies": {
56
- "typescript": ">=5.0.0"
56
+ "typescript": ">=5.0.0",
57
+ "express": "^4.18.0 || ^5.0.0"
57
58
  },
58
59
  "peerDependenciesMeta": {
59
60
  "typescript": {
60
61
  "optional": true
62
+ },
63
+ "express": {
64
+ "optional": true
61
65
  }
62
66
  },
63
67
  "publishConfig": {
64
68
  "access": "public"
65
69
  },
66
70
  "devDependencies": {
71
+ "@types/express": "^4.17.21",
67
72
  "@types/node": "^20.0.0",
68
73
  "typescript": "^5.0.0"
69
74
  }