@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.
- package/README.md +177 -72
- package/dist/bin/cli.d.ts +2 -1
- package/dist/bin/cli.d.ts.map +1 -1
- package/dist/bin/cli.js +530 -29
- package/dist/bin/cli.js.map +1 -1
- package/dist/executors/terminal-claude.d.ts +109 -0
- package/dist/executors/terminal-claude.d.ts.map +1 -0
- package/dist/executors/terminal-claude.js +493 -0
- package/dist/executors/terminal-claude.js.map +1 -0
- package/dist/server/astrid-client.d.ts +77 -0
- package/dist/server/astrid-client.d.ts.map +1 -0
- package/dist/server/astrid-client.js +125 -0
- package/dist/server/astrid-client.js.map +1 -0
- package/dist/server/index.d.ts +38 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +408 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/repo-manager.d.ts +41 -0
- package/dist/server/repo-manager.d.ts.map +1 -0
- package/dist/server/repo-manager.js +177 -0
- package/dist/server/repo-manager.js.map +1 -0
- package/dist/server/session-manager.d.ts +93 -0
- package/dist/server/session-manager.d.ts.map +1 -0
- package/dist/server/session-manager.js +217 -0
- package/dist/server/session-manager.js.map +1 -0
- package/dist/server/webhook-signature.d.ts +23 -0
- package/dist/server/webhook-signature.d.ts.map +1 -0
- package/dist/server/webhook-signature.js +74 -0
- package/dist/server/webhook-signature.js.map +1 -0
- package/package.json +7 -2
|
@@ -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.
|
|
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
|
}
|