assistme 0.1.15 → 0.2.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.
@@ -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,18 @@ 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
+ }
318
312
  async function getConversationHistory(conversationId, excludeMessageId, limit = 20) {
319
313
  const sb = getSupabase();
320
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);
@@ -346,19 +340,194 @@ async function emitEvent(messageId, eventType, eventData) {
346
340
  });
347
341
  if (error) log.warn(`Failed to emit event: ${error.message}`);
348
342
  }
349
- async function emitEvents(messageId, events) {
350
- const sb = getSupabase();
351
- const eventsJson = events.map((e) => {
352
- eventSequence++;
353
- return { type: e.type, data: e.data, seq: eventSequence };
354
- });
355
- const { error } = await sb.rpc("mcp_emit_events", {
356
- p_token_hash: getTokenHash(),
357
- p_message_id: messageId,
358
- p_events: eventsJson
359
- });
360
- if (error) log.warn(`Failed to emit events batch: ${error.message}`);
361
- }
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
+ };
362
531
 
363
532
  export {
364
533
  getConfig,
@@ -369,8 +538,6 @@ export {
369
538
  setCorrelationId,
370
539
  newCorrelationId,
371
540
  log,
372
- CLI_AGENT_ID,
373
- DAYBOX_AGENT_ID,
374
541
  getSupabase,
375
542
  loginWithToken,
376
543
  getCurrentUserId,
@@ -381,13 +548,13 @@ export {
381
548
  setSessionBusy,
382
549
  getOrCreateCliConversation,
383
550
  createTask,
384
- pollPendingTasks,
385
551
  pollAndClaimTask,
386
552
  claimTask,
387
553
  completeTask,
388
554
  failTask,
555
+ pollAndClaimJobRun,
389
556
  getConversationHistory,
390
557
  resetEventSequence,
391
558
  emitEvent,
392
- emitEvents
559
+ JobRunner
393
560
  };