rampup 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.
- package/auth.js +259 -0
- package/entitlements.js +123 -0
- package/index.js +2353 -0
- package/knowledge.js +228 -0
- package/omni/config.js +51 -0
- package/package.json +49 -0
package/knowledge.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Base Client for CLI
|
|
3
|
+
* Save and search team Q&A entries
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getIdToken } from './auth.js';
|
|
7
|
+
|
|
8
|
+
const ENTITLEMENT_API_URL = process.env.ENTITLEMENT_API_URL ||
|
|
9
|
+
'https://entitlement-service.rian-19c.workers.dev';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get user's organization (required for knowledge operations)
|
|
13
|
+
*/
|
|
14
|
+
export async function getMyOrg() {
|
|
15
|
+
const token = await getIdToken();
|
|
16
|
+
|
|
17
|
+
if (!token) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`${ENTITLEMENT_API_URL}/orgs/my`, {
|
|
23
|
+
headers: {
|
|
24
|
+
'Authorization': `Bearer ${token}`,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const data = await response.json();
|
|
34
|
+
return data.org;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.warn('[Knowledge] Failed to get org:', error.message);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Save a Q&A to the team knowledge base
|
|
43
|
+
* @param {Object} data - Knowledge entry data
|
|
44
|
+
* @param {string} data.question - The question
|
|
45
|
+
* @param {string} data.answer - The answer
|
|
46
|
+
* @param {string} [data.repoUrl] - Associated repo URL
|
|
47
|
+
* @param {string} [data.repoName] - Repository name
|
|
48
|
+
* @param {string[]} [data.tags] - Tags for categorization
|
|
49
|
+
* @param {string} [data.category] - Category: general, architecture, onboarding, debugging
|
|
50
|
+
*/
|
|
51
|
+
export async function saveKnowledge(data) {
|
|
52
|
+
const token = await getIdToken();
|
|
53
|
+
|
|
54
|
+
if (!token) {
|
|
55
|
+
throw new Error('Not logged in. Run `ramp login` first.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Get user's org
|
|
59
|
+
const org = await getMyOrg();
|
|
60
|
+
if (!org) {
|
|
61
|
+
throw new Error('You are not part of a team. Join or create a team at rampup.dev');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const response = await fetch(`${ENTITLEMENT_API_URL}/orgs/${org.id}/knowledge`, {
|
|
66
|
+
method: 'POST',
|
|
67
|
+
headers: {
|
|
68
|
+
'Authorization': `Bearer ${token}`,
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
},
|
|
71
|
+
body: JSON.stringify({
|
|
72
|
+
...data,
|
|
73
|
+
source: 'cli',
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const error = await response.json().catch(() => ({ message: 'Failed to save' }));
|
|
79
|
+
throw new Error(error.error?.message || error.message || `HTTP ${response.status}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return await response.json();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (error.message.includes('Not logged in') || error.message.includes('not part of a team')) {
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Failed to save knowledge: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Search the team knowledge base
|
|
93
|
+
* @param {Object} options - Search options
|
|
94
|
+
* @param {string} [options.query] - Search query
|
|
95
|
+
* @param {string} [options.repoUrl] - Filter by repo
|
|
96
|
+
* @param {string} [options.category] - Filter by category
|
|
97
|
+
* @param {number} [options.limit] - Max results (default 10)
|
|
98
|
+
*/
|
|
99
|
+
export async function searchKnowledge(options = {}) {
|
|
100
|
+
const token = await getIdToken();
|
|
101
|
+
|
|
102
|
+
if (!token) {
|
|
103
|
+
throw new Error('Not logged in. Run `ramp login` first.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Get user's org
|
|
107
|
+
const org = await getMyOrg();
|
|
108
|
+
if (!org) {
|
|
109
|
+
throw new Error('You are not part of a team. Join or create a team at rampup.dev');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const params = new URLSearchParams();
|
|
114
|
+
if (options.query) params.set('q', options.query);
|
|
115
|
+
if (options.repoUrl) params.set('repo', options.repoUrl);
|
|
116
|
+
if (options.category) params.set('category', options.category);
|
|
117
|
+
params.set('limit', String(options.limit || 10));
|
|
118
|
+
|
|
119
|
+
const response = await fetch(
|
|
120
|
+
`${ENTITLEMENT_API_URL}/orgs/${org.id}/knowledge?${params.toString()}`,
|
|
121
|
+
{
|
|
122
|
+
headers: {
|
|
123
|
+
'Authorization': `Bearer ${token}`,
|
|
124
|
+
'Content-Type': 'application/json',
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const error = await response.json().catch(() => ({ message: 'Search failed' }));
|
|
131
|
+
throw new Error(error.error?.message || error.message || `HTTP ${response.status}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return await response.json();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (error.message.includes('Not logged in') || error.message.includes('not part of a team')) {
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Failed to search knowledge: ${error.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get a single knowledge entry by ID
|
|
145
|
+
* @param {string} knowledgeId - The entry ID
|
|
146
|
+
*/
|
|
147
|
+
export async function getKnowledgeEntry(knowledgeId) {
|
|
148
|
+
const token = await getIdToken();
|
|
149
|
+
|
|
150
|
+
if (!token) {
|
|
151
|
+
throw new Error('Not logged in. Run `ramp login` first.');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const org = await getMyOrg();
|
|
155
|
+
if (!org) {
|
|
156
|
+
throw new Error('You are not part of a team. Join or create a team at rampup.dev');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const response = await fetch(
|
|
161
|
+
`${ENTITLEMENT_API_URL}/orgs/${org.id}/knowledge/${knowledgeId}`,
|
|
162
|
+
{
|
|
163
|
+
headers: {
|
|
164
|
+
'Authorization': `Bearer ${token}`,
|
|
165
|
+
'Content-Type': 'application/json',
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
if (response.status === 404) {
|
|
172
|
+
throw new Error('Knowledge entry not found');
|
|
173
|
+
}
|
|
174
|
+
const error = await response.json().catch(() => ({ message: 'Failed to get entry' }));
|
|
175
|
+
throw new Error(error.error?.message || error.message || `HTTP ${response.status}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return await response.json();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (error.message.includes('Not logged in') || error.message.includes('not part of a team')) {
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
throw new Error(`Failed to get knowledge entry: ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Format a knowledge entry for display in the CLI
|
|
189
|
+
* @param {Object} entry - Knowledge entry
|
|
190
|
+
*/
|
|
191
|
+
export function formatKnowledgeEntry(entry) {
|
|
192
|
+
const lines = [];
|
|
193
|
+
|
|
194
|
+
// Header with category and tags
|
|
195
|
+
const categoryEmoji = {
|
|
196
|
+
general: 'π',
|
|
197
|
+
architecture: 'ποΈ',
|
|
198
|
+
onboarding: 'π',
|
|
199
|
+
debugging: 'π',
|
|
200
|
+
}[entry.category] || 'π';
|
|
201
|
+
|
|
202
|
+
lines.push(`${categoryEmoji} ${entry.category.toUpperCase()}`);
|
|
203
|
+
|
|
204
|
+
if (entry.tags && entry.tags.length > 0) {
|
|
205
|
+
lines.push(`Tags: ${entry.tags.map(t => `#${t}`).join(' ')}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (entry.repoName) {
|
|
209
|
+
lines.push(`Repo: ${entry.repoName}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
lines.push('');
|
|
213
|
+
lines.push(`Q: ${entry.question}`);
|
|
214
|
+
lines.push('');
|
|
215
|
+
lines.push(`A: ${entry.answer}`);
|
|
216
|
+
lines.push('');
|
|
217
|
+
lines.push(`β ${entry.creatorEmail || 'Unknown'} β’ ${new Date(entry.createdAt).toLocaleDateString()} β’ ${entry.voteCount} votes`);
|
|
218
|
+
|
|
219
|
+
return lines.join('\n');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export default {
|
|
223
|
+
getMyOrg,
|
|
224
|
+
saveKnowledge,
|
|
225
|
+
searchKnowledge,
|
|
226
|
+
getKnowledgeEntry,
|
|
227
|
+
formatKnowledgeEntry,
|
|
228
|
+
};
|
package/omni/config.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// config.js - Omni AI Context Bridge configuration
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
// Detect operating system
|
|
6
|
+
const platform = process.platform;
|
|
7
|
+
|
|
8
|
+
// Default paths based on OS
|
|
9
|
+
const defaultPaths = {
|
|
10
|
+
win32: {
|
|
11
|
+
chatGpt: 'C:\\Program Files\\ChatGPT\\ChatGPT.exe',
|
|
12
|
+
claude: 'C:\\Program Files\\Claude\\Claude.exe'
|
|
13
|
+
},
|
|
14
|
+
darwin: {
|
|
15
|
+
chatGpt: '/Applications/ChatGPT.app',
|
|
16
|
+
claude: '/Applications/Claude.app'
|
|
17
|
+
},
|
|
18
|
+
linux: {
|
|
19
|
+
chatGpt: '/usr/bin/chatgpt',
|
|
20
|
+
claude: '/usr/bin/claude'
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
// Path to store context data
|
|
26
|
+
contextStorePath: path.join(os.homedir(), '.ramp', 'omni-contexts.json'),
|
|
27
|
+
|
|
28
|
+
// Paths to desktop applications
|
|
29
|
+
paths: {
|
|
30
|
+
chatGpt: process.env.CHATGPT_PATH || defaultPaths[platform]?.chatGpt,
|
|
31
|
+
claude: process.env.CLAUDE_PATH || defaultPaths[platform]?.claude
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
// Web app URLs
|
|
35
|
+
urls: {
|
|
36
|
+
chatGpt: 'https://chat.openai.com',
|
|
37
|
+
claude: 'https://claude.ai'
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// CSS selectors for web interfaces
|
|
41
|
+
selectors: {
|
|
42
|
+
chatGpt: {
|
|
43
|
+
lastMessage: '.markdown',
|
|
44
|
+
inputBox: 'textarea[data-id="root"]'
|
|
45
|
+
},
|
|
46
|
+
claude: {
|
|
47
|
+
lastMessage: '.claude-response-text',
|
|
48
|
+
inputBox: 'textarea[placeholder="Message Claudeβ¦"]'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rampup",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Ramp - Understand any codebase in hours. AI-powered developer onboarding CLI.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ramp": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"auth.js",
|
|
12
|
+
"entitlements.js",
|
|
13
|
+
"knowledge.js",
|
|
14
|
+
"omni/"
|
|
15
|
+
],
|
|
16
|
+
"keywords": [
|
|
17
|
+
"cli",
|
|
18
|
+
"ai",
|
|
19
|
+
"codebase",
|
|
20
|
+
"onboarding",
|
|
21
|
+
"learning",
|
|
22
|
+
"developer",
|
|
23
|
+
"documentation"
|
|
24
|
+
],
|
|
25
|
+
"author": "Ramp <hello@rampup.dev>",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"homepage": "https://rampup.dev",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/rampup-dev/ramp.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/rampup-dev/ramp/issues"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@anthropic-ai/sdk": "^0.70.1",
|
|
40
|
+
"chalk": "^4.1.2",
|
|
41
|
+
"clipboardy": "^3.0.0",
|
|
42
|
+
"commander": "^11.1.0",
|
|
43
|
+
"firebase": "^10.14.1",
|
|
44
|
+
"inquirer": "^8.2.6",
|
|
45
|
+
"open": "^9.1.0",
|
|
46
|
+
"openai": "^4.0.0",
|
|
47
|
+
"ora": "^5.4.1"
|
|
48
|
+
}
|
|
49
|
+
}
|