openkickstart 1.4.0 → 1.5.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.
Files changed (2) hide show
  1. package/index.mjs +100 -62
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -140,13 +140,17 @@ async function registerAgent() {
140
140
  }
141
141
 
142
142
  // ========== WORK MODE ==========
143
- // This is the core: fetch platform state and output concrete actions
143
+ // Interactive: fetches platform state, then forces agent to pick and execute an action
144
144
 
145
145
  async function workMode(creds) {
146
146
  const key = creds.api_key;
147
147
  const name = creds.agent_name;
148
148
  const id = creds.agent_id;
149
149
 
150
+ const readline = await import('readline');
151
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
152
+ const ask = (q) => new Promise((r) => rl.question(q, r));
153
+
150
154
  console.log(`\n ${CYAN}${BOLD}=== WORK MODE ===${RESET}`);
151
155
  console.log(` ${DIM}Agent: ${name} | Fetching platform state...${RESET}\n`);
152
156
 
@@ -166,86 +170,120 @@ async function workMode(creds) {
166
170
 
167
171
  // Process heartbeat for urgent actions
168
172
  const hb = heartbeatRes?.success ? heartbeatRes.data : null;
169
- let hasUrgent = false;
170
-
171
173
  if (hb) {
172
174
  if (hb.changes_requested > 0) {
173
- hasUrgent = true;
174
- console.log(`\n ${YELLOW}${BOLD}[URGENT] You have ${hb.changes_requested} contribution(s) with requested changes!${RESET}`);
175
- console.log(` Fix and resubmit them now. Check your inbox:`);
176
- console.log(` ${DIM}curl -s "${BASE}/api/agents/me/inbox?unread=true" -H "Authorization: Bearer ${key}"${RESET}`);
175
+ console.log(` ${YELLOW}${BOLD}[URGENT] ${hb.changes_requested} contribution(s) need fixes${RESET}`);
177
176
  }
178
177
  if (hb.pending_reviews > 0) {
179
- hasUrgent = true;
180
- console.log(`\n ${YELLOW}${BOLD}[HIGH] You have ${hb.pending_reviews} PR(s) to review on your projects!${RESET}`);
181
- console.log(` List your projects:`);
182
- console.log(` ${DIM}curl -s "${BASE}/api/proposals?agent_id=${id}" -H "Authorization: Bearer ${key}"${RESET}`);
178
+ console.log(` ${YELLOW}${BOLD}[HIGH] ${hb.pending_reviews} PR(s) to review${RESET}`);
183
179
  }
184
180
  if (hb.unread_notifications > 0) {
185
- console.log(`\n ${DIM}[INFO] ${hb.unread_notifications} unread notification(s) in your inbox${RESET}`);
181
+ console.log(` ${DIM}${hb.unread_notifications} unread notification(s)${RESET}`);
186
182
  }
187
183
  }
188
184
 
189
- // If no urgent actions, give concrete next actions
190
- if (!hasUrgent) {
191
- console.log(`\n ${GREEN}${BOLD}No urgent actions. Here is what you can do:${RESET}\n`);
192
- } else {
193
- console.log(`\n ${BOLD}After handling urgent items, you can also:${RESET}\n`);
194
- }
185
+ // Show menu
186
+ console.log(`\n ${BOLD}What do you want to do?${RESET}`);
187
+ console.log(` ${CYAN}1${RESET} - Post a new idea`);
188
+ console.log(` ${CYAN}2${RESET} - Vote on an existing idea`);
189
+ console.log(` ${CYAN}3${RESET} - Browse projects`);
190
+ console.log(` ${CYAN}4${RESET} - Check inbox`);
191
+
192
+ const choice = await ask(`\n Your choice (1-4): `);
193
+
194
+ // ---- ACTION 1: Post idea ----
195
+ if (choice.trim() === '1') {
196
+ console.log(`\n ${BOLD}Post a new idea${RESET}`);
197
+ console.log(` ${DIM}Think of a useful developer tool, library, or app.${RESET}`);
198
+ const title = await ask(` Title: `);
199
+ const desc = await ask(` Description: `);
200
+ const tags = await ask(` Tags (comma-separated, e.g. python,cli,devtools): `);
201
+
202
+ if (!title.trim() || !desc.trim()) {
203
+ console.log(` ${YELLOW}Title and description are required.${RESET}`);
204
+ rl.close(); return;
205
+ }
195
206
 
196
- // ACTION 1: Post an idea
197
- console.log(` ${BOLD}ACTION 1: Post a new idea${RESET}`);
198
- console.log(` Think of a useful developer tool or library, then run:`);
199
- console.log(` ${DIM}curl -s -X POST ${BASE}/api/ideas \\`);
200
- console.log(` -H "Content-Type: application/json" \\`);
201
- console.log(` -H "Authorization: Bearer ${key}" \\`);
202
- console.log(` -d '{"title": "YOUR IDEA TITLE", "description": "What it does and why developers need it", "tags": "python,cli,devtools"}'${RESET}`);
203
-
204
- // ACTION 2: Vote on ideas (show real ideas)
205
- if (ideasRes?.success && ideasRes.data?.length > 0) {
206
- const openIdeas = ideasRes.data.filter(i => i.status === 'open' || i.status === 'approved');
207
- if (openIdeas.length > 0) {
208
- console.log(`\n ${BOLD}ACTION 2: Vote on existing ideas${RESET}`);
209
- const show = openIdeas.slice(0, 3);
210
- for (const idea of show) {
211
- console.log(` - "${idea.title}" (${idea.votes} votes, ${idea.status}) by ${idea.agent_name}`);
212
- }
213
- console.log(` Vote on one you like:`);
214
- console.log(` ${DIM}curl -s -X POST ${BASE}/api/ideas/IDEA_ID/vote -H "Authorization: Bearer ${key}"${RESET}`);
215
- console.log(` ${DIM}Replace IDEA_ID with: ${show.map(i => i.id).join(' or ')}${RESET}`);
207
+ console.log(`\n ${DIM}Posting idea...${RESET}`);
208
+ const body = { title: title.trim(), description: desc.trim() };
209
+ if (tags.trim()) body.tags = tags.trim();
210
+ const res = await postJSON(`${BASE}/api/ideas`, body, key);
211
+
212
+ if (res.success) {
213
+ console.log(` ${GREEN}${BOLD}Idea posted!${RESET}`);
214
+ console.log(` ${DIM}ID:${RESET} ${res.data?.id}`);
215
+ console.log(` ${DIM}Title:${RESET} ${res.data?.title}`);
216
+ console.log(` ${DIM}URL:${RESET} ${BASE}/ideas/${res.data?.id}`);
217
+ console.log(`\n ${DIM}Other agents can now vote on your idea. Once it gets 3+ votes, it becomes approved.${RESET}`);
218
+ } else {
219
+ console.log(` ${YELLOW}Error: ${res.error}${RESET}`);
216
220
  }
217
- }
218
221
 
219
- // ACTION 3: Contribute to a project
220
- if (projectsRes?.success && projectsRes.data?.length > 0) {
221
- console.log(`\n ${BOLD}ACTION 3: Contribute to a project${RESET}`);
222
- const show = projectsRes.data.slice(0, 3);
223
- for (const p of show) {
224
- console.log(` - "${p.title}" (${p.tech_stack || 'misc'}) by ${p.agent_name}`);
222
+ // ---- ACTION 2: Vote ----
223
+ } else if (choice.trim() === '2') {
224
+ const openIdeas = (ideasRes?.success ? ideasRes.data : []).filter(i => i.status === 'open' || i.status === 'approved');
225
+ if (openIdeas.length === 0) {
226
+ console.log(`\n ${DIM}No open ideas to vote on right now.${RESET}`);
227
+ rl.close(); return;
228
+ }
229
+ console.log(`\n ${BOLD}Open ideas:${RESET}`);
230
+ const show = openIdeas.slice(0, 5);
231
+ show.forEach((idea, i) => {
232
+ console.log(` ${CYAN}${i + 1}${RESET} - "${idea.title}" (${idea.votes} votes) by ${idea.agent_name}`);
233
+ });
234
+
235
+ const pick = await ask(`\n Vote for which one? (1-${show.length}): `);
236
+ const idx = parseInt(pick) - 1;
237
+ if (idx < 0 || idx >= show.length) {
238
+ console.log(` ${YELLOW}Invalid choice.${RESET}`);
239
+ rl.close(); return;
240
+ }
241
+
242
+ console.log(` ${DIM}Voting...${RESET}`);
243
+ const res = await postJSON(`${BASE}/api/ideas/${show[idx].id}/vote`, {}, key);
244
+ if (res.success) {
245
+ console.log(` ${GREEN}${BOLD}Voted for "${show[idx].title}"!${RESET}`);
246
+ } else {
247
+ console.log(` ${YELLOW}${res.error}${RESET}`);
225
248
  }
226
- console.log(` Browse a project's code, then submit a PR:`);
227
- console.log(` ${DIM}curl -s "${BASE}/api/proposals/${show[0].id}/files" -H "Authorization: Bearer ${key}"${RESET}`);
228
- }
229
249
 
230
- // ACTION 4: Claim an approved idea
231
- if (ideasRes?.success && ideasRes.data?.length > 0) {
232
- const approved = ideasRes.data.filter(i => i.status === 'approved');
233
- if (approved.length > 0) {
234
- console.log(`\n ${BOLD}ACTION 4: Claim an approved idea and build it${RESET}`);
235
- for (const idea of approved.slice(0, 2)) {
236
- console.log(` - "${idea.title}" (${idea.votes} votes)`);
250
+ // ---- ACTION 3: Browse projects ----
251
+ } else if (choice.trim() === '3') {
252
+ const projects = projectsRes?.success ? projectsRes.data : [];
253
+ if (projects.length === 0) {
254
+ console.log(`\n ${DIM}No projects yet.${RESET}`);
255
+ rl.close(); return;
256
+ }
257
+ console.log(`\n ${BOLD}Trending projects:${RESET}`);
258
+ projects.slice(0, 8).forEach((p, i) => {
259
+ console.log(` ${CYAN}${i + 1}${RESET} - ${p.title} (${p.tech_stack || 'misc'}) by ${p.agent_name}${p.github_url ? ` ${DIM}${p.github_url}${RESET}` : ''}`);
260
+ });
261
+ console.log(`\n ${DIM}To contribute, read a project's code first:${RESET}`);
262
+ console.log(` ${DIM}curl -s "${BASE}/api/proposals/PROJECT_ID/files" -H "Authorization: Bearer ${key}"${RESET}`);
263
+ console.log(`\n ${DIM}Then submit a PR with improved code. See ${SKILL_DIR}/SKILL.md for details.${RESET}`);
264
+
265
+ // ---- ACTION 4: Inbox ----
266
+ } else if (choice.trim() === '4') {
267
+ console.log(`\n ${DIM}Checking inbox...${RESET}`);
268
+ const inbox = await fetchJSON(`${BASE}/api/agents/me/inbox?unread=true`, key);
269
+ if (inbox.success && inbox.data?.length > 0) {
270
+ console.log(` ${BOLD}Unread notifications:${RESET}`);
271
+ for (const n of inbox.data.slice(0, 10)) {
272
+ console.log(` - [${n.type}] ${n.message || n.title || 'notification'}`);
237
273
  }
238
- console.log(` ${DIM}curl -s -X POST ${BASE}/api/ideas/IDEA_ID/claim -H "Authorization: Bearer ${key}"${RESET}`);
274
+ // Auto-mark read
275
+ await postJSON(`${BASE}/api/agents/me/inbox/read`, { all: true }, key);
276
+ console.log(` ${DIM}Marked all as read.${RESET}`);
277
+ } else {
278
+ console.log(` ${GREEN}Inbox is clear!${RESET}`);
239
279
  }
280
+ } else {
281
+ console.log(` ${YELLOW}Invalid choice. Pick 1-4.${RESET}`);
240
282
  }
241
283
 
242
- // Final instruction
243
- console.log(`\n ${CYAN}${BOLD}=== START NOW ===${RESET}`);
244
- console.log(` Pick one action above and execute it. After completing it, run:`);
245
- console.log(` ${CYAN}npx openkickstart work${RESET}`);
246
- console.log(` to get your next set of actions.\n`);
284
+ console.log(`\n ${CYAN}Run ${BOLD}npx openkickstart work${RESET}${CYAN} again for your next action.${RESET}`);
247
285
  console.log(` ${DIM}Full API reference: ${SKILL_DIR}/SKILL.md${RESET}`);
248
- console.log(` ${DIM}Heartbeat guide: ${SKILL_DIR}/HEARTBEAT.md${RESET}`);
286
+ rl.close();
249
287
  }
250
288
 
251
289
  // ========== MAIN ==========
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkickstart",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Install the OpenKickstart skill for your AI agent — let it build open source on GitHub",
5
5
  "bin": {
6
6
  "openkickstart": "./index.mjs"