assistme 0.1.14 → 0.2.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.
@@ -116,8 +116,6 @@ var log = {
116
116
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
117
117
  import { join } from "path";
118
118
  import { homedir } from "os";
119
- var CLI_AGENT_ID = "00000000-0000-0000-0000-000000000001";
120
- var DAYBOX_AGENT_ID = "00000000-0000-0000-0000-000000000002";
121
119
  var AUTH_DIR = join(homedir(), ".config", "assistme");
122
120
  var AUTH_FILE = join(AUTH_DIR, "auth.json");
123
121
  function ensureAuthDir() {
@@ -254,22 +252,6 @@ async function createTask(conversationId, _userId, sessionId, prompt) {
254
252
  if (error) throw new Error(`Failed to create task: ${error.message}`);
255
253
  return { ...data, prompt };
256
254
  }
257
- async function pollPendingTasks(sessionId) {
258
- const sb = getSupabase();
259
- const { data, error } = await sb.rpc("mcp_poll_tasks", {
260
- p_token_hash: getTokenHash(),
261
- p_session_id: sessionId
262
- });
263
- if (error) {
264
- log.warn(`Task poll failed: ${error.message}`);
265
- return [];
266
- }
267
- const rows = data || [];
268
- return rows.map((row) => ({
269
- ...row,
270
- prompt: row.metadata?.prompt || row.content || ""
271
- }));
272
- }
273
255
  async function pollAndClaimTask(sessionId) {
274
256
  const sb = getSupabase();
275
257
  const { data, error } = await sb.rpc("mcp_poll_and_claim_task", {
@@ -315,6 +297,33 @@ async function failTask(messageId, errorMessage) {
315
297
  });
316
298
  if (error) log.error(`Failed to update task status: ${error.message}`);
317
299
  }
300
+ async function pollAndClaimJobRun(userId) {
301
+ const sb = getSupabase();
302
+ const { data, error } = await sb.rpc("claim_pending_job_run", {
303
+ p_user_id: userId
304
+ });
305
+ if (error) {
306
+ log.debug(`Job run poll failed: ${error.message}`);
307
+ return null;
308
+ }
309
+ if (!data) return null;
310
+ return data;
311
+ }
312
+ async function getConversationHistory(conversationId, excludeMessageId, limit = 20) {
313
+ const sb = getSupabase();
314
+ const { data, error } = await sb.from("conversation_messages").select("id, role, content, status, metadata, created_at").eq("conversation_id", conversationId).in("status", ["completed", "failed"]).neq("id", excludeMessageId).order("created_at", { ascending: false }).limit(limit);
315
+ if (error) {
316
+ log.debug(`Failed to fetch conversation history: ${error.message}`);
317
+ return [];
318
+ }
319
+ const rows = data || [];
320
+ return rows.reverse().map((row) => {
321
+ const prompt = row.metadata?.prompt || "";
322
+ const content = row.content || "";
323
+ const response = row.status === "failed" ? `[Task failed] ${content}` : content;
324
+ return { prompt, response };
325
+ }).filter((entry) => entry.prompt && entry.response);
326
+ }
318
327
  var eventSequence = 0;
319
328
  function resetEventSequence() {
320
329
  eventSequence = 0;
@@ -331,19 +340,194 @@ async function emitEvent(messageId, eventType, eventData) {
331
340
  });
332
341
  if (error) log.warn(`Failed to emit event: ${error.message}`);
333
342
  }
334
- async function emitEvents(messageId, events) {
335
- const sb = getSupabase();
336
- const eventsJson = events.map((e) => {
337
- eventSequence++;
338
- return { type: e.type, data: e.data, seq: eventSequence };
339
- });
340
- const { error } = await sb.rpc("mcp_emit_events", {
341
- p_token_hash: getTokenHash(),
342
- p_message_id: messageId,
343
- p_events: eventsJson
344
- });
345
- if (error) log.warn(`Failed to emit events batch: ${error.message}`);
346
- }
343
+
344
+ // src/agent/job-runner.ts
345
+ var JobRunner = class {
346
+ userId;
347
+ constructor(userId) {
348
+ this.userId = userId;
349
+ }
350
+ /**
351
+ * Load a job and its linked skills from the database.
352
+ * Skills are the agent's *capabilities* — not a fixed execution plan.
353
+ */
354
+ async loadJob(jobName) {
355
+ try {
356
+ const sb = getSupabase();
357
+ const { data, error } = await sb.rpc("get_job_with_skills", {
358
+ p_user_id: this.userId,
359
+ p_job_name: jobName
360
+ });
361
+ if (error || !data || data.length === 0) {
362
+ return null;
363
+ }
364
+ const rows = data;
365
+ const first = rows[0];
366
+ return {
367
+ jobId: first.job_id,
368
+ jobName: first.job_name,
369
+ jobDescription: first.job_description,
370
+ skills: rows.map((row) => ({
371
+ skillId: row.skill_id,
372
+ skillName: row.skill_name,
373
+ skillDescription: row.skill_description || "",
374
+ skillEmoji: row.skill_emoji || "",
375
+ skillContent: row.skill_content || ""
376
+ }))
377
+ };
378
+ } catch (err) {
379
+ log.debug(`Failed to load job "${jobName}": ${err}`);
380
+ return null;
381
+ }
382
+ }
383
+ /**
384
+ * List all jobs for the user.
385
+ */
386
+ async listJobs() {
387
+ try {
388
+ const sb = getSupabase();
389
+ const { data: jobs, error } = await sb.from("agent_jobs").select("id, name, description").eq("user_id", this.userId).eq("is_active", true).order("name");
390
+ if (error || !jobs) return [];
391
+ const result = [];
392
+ for (const job of jobs) {
393
+ const { count } = await sb.from("agent_job_skills").select("id", { count: "exact", head: true }).eq("job_id", job.id);
394
+ result.push({
395
+ id: job.id,
396
+ name: job.name,
397
+ description: job.description,
398
+ skillCount: count || 0
399
+ });
400
+ }
401
+ return result;
402
+ } catch (err) {
403
+ log.debug(`Failed to list jobs: ${err}`);
404
+ return [];
405
+ }
406
+ }
407
+ /**
408
+ * Create a job run record.
409
+ * This is just a timestamp + status tracker. The actual execution trace
410
+ * lives in the conversation transcript (message_events).
411
+ */
412
+ async createRun(jobId, options) {
413
+ try {
414
+ const sb = getSupabase();
415
+ const { data, error } = await sb.rpc("create_job_run", {
416
+ p_user_id: this.userId,
417
+ p_job_id: jobId,
418
+ p_session_id: options?.sessionId || null,
419
+ p_message_id: options?.messageId || null,
420
+ p_trigger_type: options?.triggerType || "manual"
421
+ });
422
+ if (error) {
423
+ log.debug(`Failed to create job run: ${error.message}`);
424
+ return null;
425
+ }
426
+ return data;
427
+ } catch (err) {
428
+ log.debug(`Job run creation error: ${err}`);
429
+ return null;
430
+ }
431
+ }
432
+ /**
433
+ * Mark a job run as completed/failed.
434
+ * Throws on failure so callers can handle (e.g. avoid duplicate execution).
435
+ */
436
+ async completeRun(runId, status = "completed", summary) {
437
+ const sb = getSupabase();
438
+ const { error } = await sb.rpc("complete_job_run", {
439
+ p_run_id: runId,
440
+ p_status: status,
441
+ p_summary: summary?.slice(0, 1e4) || null,
442
+ p_user_id: this.userId
443
+ });
444
+ if (error) {
445
+ log.error(`Failed to mark run ${runId} as ${status}: ${error.message}`);
446
+ throw new Error(`Run completion failed: ${error.message}`);
447
+ }
448
+ }
449
+ /**
450
+ * Get recent job run history.
451
+ */
452
+ async getRunHistory(jobName, limit = 10) {
453
+ try {
454
+ const sb = getSupabase();
455
+ const { data, error } = await sb.rpc("get_job_runs", {
456
+ p_user_id: this.userId,
457
+ p_job_name: jobName || null,
458
+ p_limit: limit
459
+ });
460
+ if (error || !data) return [];
461
+ return data.map((row) => ({
462
+ runId: row.run_id,
463
+ jobName: row.job_name,
464
+ status: row.status,
465
+ triggerType: row.trigger_type,
466
+ startedAt: row.started_at,
467
+ completedAt: row.completed_at || null,
468
+ summary: row.summary || null
469
+ }));
470
+ } catch (err) {
471
+ log.debug(`Run history error: ${err}`);
472
+ return [];
473
+ }
474
+ }
475
+ /**
476
+ * Build the agentic prompt for the agent to execute a job.
477
+ *
478
+ * This does NOT prescribe a fixed sequence. Instead, it tells the agent
479
+ * the job's goal and lists available skills as capabilities. The agent
480
+ * decides dynamically which skills to use, in what order, and how to
481
+ * chain them based on what it discovers at runtime.
482
+ */
483
+ buildJobPrompt(job, runId) {
484
+ let prompt = `## Job: ${job.jobName}
485
+ `;
486
+ prompt += `*${job.jobDescription}*
487
+
488
+ `;
489
+ prompt += `**Run ID:** ${runId}
490
+
491
+ `;
492
+ prompt += `You are now acting as "${job.jobName}". `;
493
+ prompt += `Your goal is to accomplish the objectives described above using the skills and tools available to you.
494
+
495
+ `;
496
+ prompt += `### Available Skills
497
+ `;
498
+ prompt += `These skills are your capabilities for this job. `;
499
+ prompt += `Use \`skill_invoke\` to load any skill's full instructions when you need it. `;
500
+ prompt += `You do NOT need to use all of them \u2014 pick the ones relevant to the current situation.
501
+
502
+ `;
503
+ for (const skill of job.skills) {
504
+ const emoji = skill.skillEmoji ? `${skill.skillEmoji} ` : "";
505
+ prompt += `- **${emoji}${skill.skillName}**: ${skill.skillDescription}
506
+ `;
507
+ }
508
+ prompt += `
509
+ ### How to Work
510
+ `;
511
+ prompt += `- **Be agentic**: Decide what to do based on what you discover. `;
512
+ prompt += `If checking Slack reveals a request that requires GitHub work, go do the GitHub work immediately \u2014 don't just note it for later.
513
+ `;
514
+ prompt += `- **Chain dynamically**: One skill's output should inform your next action. `;
515
+ prompt += `For example, if you find an assigned GitHub issue, use your coding skills to implement it.
516
+ `;
517
+ prompt += `- **Skip what's irrelevant**: If a capability doesn't apply right now, skip it.
518
+ `;
519
+ prompt += `- **Use tools directly too**: You also have browser, file, and shell tools. `;
520
+ prompt += `Use them directly when a skill isn't needed \u2014 skills are guides, not mandatory steps.
521
+ `;
522
+ prompt += `- **Respond and act**: If you find messages or issues that need replies, reply to them. `;
523
+ prompt += `If you find code tasks, implement them.
524
+
525
+ `;
526
+ prompt += `When finished, provide a summary of what you accomplished and any items that need the user's attention.
527
+ `;
528
+ return prompt;
529
+ }
530
+ };
347
531
 
348
532
  export {
349
533
  getConfig,
@@ -354,8 +538,6 @@ export {
354
538
  setCorrelationId,
355
539
  newCorrelationId,
356
540
  log,
357
- CLI_AGENT_ID,
358
- DAYBOX_AGENT_ID,
359
541
  getSupabase,
360
542
  loginWithToken,
361
543
  getCurrentUserId,
@@ -366,12 +548,13 @@ export {
366
548
  setSessionBusy,
367
549
  getOrCreateCliConversation,
368
550
  createTask,
369
- pollPendingTasks,
370
551
  pollAndClaimTask,
371
552
  claimTask,
372
553
  completeTask,
373
554
  failTask,
555
+ pollAndClaimJobRun,
556
+ getConversationHistory,
374
557
  resetEventSequence,
375
558
  emitEvent,
376
- emitEvents
559
+ JobRunner
377
560
  };