assistme 0.2.5 → 0.2.6

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/dist/index.js CHANGED
@@ -3179,19 +3179,17 @@ ${content}`;
3179
3179
  response += `**Your task:** Analyze this job description and decompose it into 4-10 automatable skills.
3180
3180
 
3181
3181
  `;
3182
- response += `**IMPORTANT \u2014 Confirmation workflow:**
3182
+ response += `**IMPORTANT \u2014 You MUST use request_user_confirmation before creating skills:**
3183
3183
  `;
3184
- response += `1. First, analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).
3184
+ response += `1. Analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).
3185
3185
  `;
3186
- response += `2. Then call \`request_user_confirmation\` to present these skills to the user for approval BEFORE creating any.
3186
+ response += `2. Call \`request_user_confirmation\` with the formatted skill list as "message" and these options:
3187
3187
  `;
3188
- response += ` - message: show a formatted list of all proposed skills
3188
+ response += ` - options: [{label: "Approve All", action_key: "approve_all", description: "Create all proposed skills"}, {label: "Cancel", action_key: "cancel", description: "Do not create any skills"}]
3189
3189
  `;
3190
- response += ` - options: [{label: "Approve All", value: "approve_all"}, {label: "Cancel", value: "cancel"}]
3190
+ response += `3. WAIT for the response. If action_key is "approve_all", create all skills using \`skill_create\`. If "cancel", stop.
3191
3191
  `;
3192
- response += `3. If the user approves, create all skills using \`skill_create\` for each.
3193
- `;
3194
- response += `4. If the user cancels, stop without creating anything.
3192
+ response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling request_user_confirmation first.
3195
3193
 
3196
3194
  `;
3197
3195
  response += `For each skill, call \`skill_create\` with:
@@ -3361,18 +3359,18 @@ ${content}`;
3361
3359
  // ── User Confirmation Tool ─────────────────────────────────
3362
3360
  tool(
3363
3361
  "request_user_confirmation",
3364
- "Pause and ask the user for approval or input via the web UI. Returns the user's response. Use this before creating skills, making irreversible changes, etc.",
3362
+ "Pause and ask the user for approval or input via the web UI. Returns the user's chosen action_key. Use this BEFORE creating skills, making irreversible changes, etc. The agent will block until the user responds or the timeout expires.",
3365
3363
  {
3366
3364
  message: z.string().describe("What to show the user (supports markdown)"),
3367
3365
  options: z.array(z.object({
3368
- label: z.string(),
3369
- value: z.string(),
3370
- description: z.string().optional()
3366
+ label: z.string().describe("Button label shown to user"),
3367
+ action_key: z.string().describe("Machine-readable key returned when selected"),
3368
+ description: z.string().optional().describe("Tooltip/description for this option")
3371
3369
  })).describe("Buttons/options to show the user"),
3372
3370
  timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)")
3373
3371
  },
3374
3372
  async (args) => {
3375
- const actionId = crypto.randomUUID();
3373
+ const actionId = `action_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3376
3374
  const timeout = (args.timeout_seconds || 300) * 1e3;
3377
3375
  const actionData = {
3378
3376
  id: actionId,
@@ -3383,20 +3381,24 @@ ${content}`;
3383
3381
  };
3384
3382
  try {
3385
3383
  await setActionRequest(taskId, actionData);
3386
- await emitEvent(taskId, "user_action_request", actionData);
3384
+ log.info(`Action request ${actionId} stored in metadata, waiting for user response...`);
3385
+ emitEvent(taskId, "user_action_request", actionData).catch(() => {
3386
+ });
3387
3387
  const startTime = Date.now();
3388
3388
  const pollInterval = 2e3;
3389
3389
  while (Date.now() - startTime < timeout) {
3390
3390
  const response = await pollActionResponse(taskId);
3391
3391
  if (response) {
3392
- log.info(`User responded to action request ${actionId}: ${JSON.stringify(response)}`);
3392
+ const actionKey = response.action_key || response.action || "";
3393
+ const label = response.label || actionKey;
3394
+ log.info(`User responded: ${label} (${actionKey})`);
3393
3395
  return {
3394
3396
  content: [{
3395
3397
  type: "text",
3396
3398
  text: JSON.stringify({
3397
3399
  status: "responded",
3398
- action: response.action || response.value,
3399
- response
3400
+ action_key: actionKey,
3401
+ label
3400
3402
  })
3401
3403
  }]
3402
3404
  };
@@ -3414,6 +3416,7 @@ ${content}`;
3414
3416
  }]
3415
3417
  };
3416
3418
  } catch (err) {
3419
+ log.error(`request_user_confirmation failed: ${err}`);
3417
3420
  return {
3418
3421
  content: [{
3419
3422
  type: "text",
@@ -3721,7 +3724,7 @@ Available capabilities:
3721
3724
 
3722
3725
  5. JOB AUTOMATION:
3723
3726
  - When the user describes their job/role/daily work, use skill_generate to decompose it into automatable skills
3724
- - First call without auto_create to show the plan, then with auto_create:true after user confirms
3727
+ - ALWAYS use request_user_confirmation to get user approval before creating skills \u2014 never create skills without approval
3725
3728
  - Use job_run to start a job \u2014 it gives you the job's goal and available skills as capabilities
3726
3729
  - When running a job, be AGENTIC: decide dynamically what to do based on what you discover
3727
3730
  - Do NOT follow a fixed sequence \u2014 if checking Slack reveals a task that needs GitHub, go do GitHub immediately
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistme",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "AssistMe CLI Agent - AI-powered assistant that controls your real browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -441,13 +441,12 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
441
441
  }
442
442
 
443
443
  response += `**Your task:** Analyze this job description and decompose it into 4-10 automatable skills.\n\n`;
444
- response += `**IMPORTANT — Confirmation workflow:**\n`;
445
- response += `1. First, analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).\n`;
446
- response += `2. Then call \`request_user_confirmation\` to present these skills to the user for approval BEFORE creating any.\n`;
447
- response += ` - message: show a formatted list of all proposed skills\n`;
448
- response += ` - options: [{label: "Approve All", value: "approve_all"}, {label: "Cancel", value: "cancel"}]\n`;
449
- response += `3. If the user approves, create all skills using \`skill_create\` for each.\n`;
450
- response += `4. If the user cancels, stop without creating anything.\n\n`;
444
+ response += `**IMPORTANT — You MUST use request_user_confirmation before creating skills:**\n`;
445
+ response += `1. Analyze the job and draft a list of proposed skills (name, emoji, one-line description for each).\n`;
446
+ response += `2. Call \`request_user_confirmation\` with the formatted skill list as "message" and these options:\n`;
447
+ response += ` - options: [{label: "Approve All", action_key: "approve_all", description: "Create all proposed skills"}, {label: "Cancel", action_key: "cancel", description: "Do not create any skills"}]\n`;
448
+ response += `3. WAIT for the response. If action_key is "approve_all", create all skills using \`skill_create\`. If "cancel", stop.\n`;
449
+ response += `4. Do NOT ask for confirmation in text. Do NOT create skills without calling request_user_confirmation first.\n\n`;
451
450
  response += `For each skill, call \`skill_create\` with:\n`;
452
451
  response += `- name: kebab-case name (e.g. "slack-message-check")\n`;
453
452
  response += `- description: one-line description\n`;
@@ -610,18 +609,19 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
610
609
  tool(
611
610
  "request_user_confirmation",
612
611
  "Pause and ask the user for approval or input via the web UI. " +
613
- "Returns the user's response. Use this before creating skills, making irreversible changes, etc.",
612
+ "Returns the user's chosen action_key. Use this BEFORE creating skills, making irreversible changes, etc. " +
613
+ "The agent will block until the user responds or the timeout expires.",
614
614
  {
615
615
  message: z.string().describe("What to show the user (supports markdown)"),
616
616
  options: z.array(z.object({
617
- label: z.string(),
618
- value: z.string(),
619
- description: z.string().optional(),
617
+ label: z.string().describe("Button label shown to user"),
618
+ action_key: z.string().describe("Machine-readable key returned when selected"),
619
+ description: z.string().optional().describe("Tooltip/description for this option"),
620
620
  })).describe("Buttons/options to show the user"),
621
621
  timeout_seconds: z.number().optional().describe("How long to wait for response (default: 300)"),
622
622
  },
623
623
  async (args) => {
624
- const actionId = crypto.randomUUID();
624
+ const actionId = `action_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
625
625
  const timeout = (args.timeout_seconds || 300) * 1000;
626
626
 
627
627
  const actionData = {
@@ -633,37 +633,38 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
633
633
  };
634
634
 
635
635
  try {
636
- // 1. Store action request in message metadata via RPC
636
+ // Store action request in message metadata via RPC — UI reads this
637
637
  await setActionRequest(taskId, actionData);
638
+ log.info(`Action request ${actionId} stored in metadata, waiting for user response...`);
638
639
 
639
- // 2. Emit user_action_request event so web UI renders buttons
640
- await emitEvent(taskId, "user_action_request", actionData);
640
+ // Also emit event for real-time notification (best-effort)
641
+ emitEvent(taskId, "user_action_request", actionData).catch(() => {});
641
642
 
642
- // 3. Poll for response
643
+ // Poll for response
643
644
  const startTime = Date.now();
644
645
  const pollInterval = 2000;
645
646
 
646
647
  while (Date.now() - startTime < timeout) {
647
648
  const response = await pollActionResponse(taskId);
648
649
  if (response) {
649
- log.info(`User responded to action request ${actionId}: ${JSON.stringify(response)}`);
650
+ const actionKey = (response.action_key || response.action || "") as string;
651
+ const label = (response.label || actionKey) as string;
652
+ log.info(`User responded: ${label} (${actionKey})`);
650
653
  return {
651
654
  content: [{
652
655
  type: "text",
653
656
  text: JSON.stringify({
654
657
  status: "responded",
655
- action: response.action || response.value,
656
- response,
658
+ action_key: actionKey,
659
+ label,
657
660
  }),
658
661
  }],
659
662
  };
660
663
  }
661
664
 
662
- // Wait before next poll
663
665
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
664
666
  }
665
667
 
666
- // Timeout
667
668
  log.warn(`Action request ${actionId} timed out after ${args.timeout_seconds || 300}s`);
668
669
  return {
669
670
  content: [{
@@ -675,6 +676,7 @@ export function createAgentToolsServer(deps: AgentToolsDeps): McpSdkServerConfig
675
676
  }],
676
677
  };
677
678
  } catch (err) {
679
+ log.error(`request_user_confirmation failed: ${err}`);
678
680
  return {
679
681
  content: [{
680
682
  type: "text",
@@ -68,7 +68,7 @@ Available capabilities:
68
68
 
69
69
  5. JOB AUTOMATION:
70
70
  - When the user describes their job/role/daily work, use skill_generate to decompose it into automatable skills
71
- - First call without auto_create to show the plan, then with auto_create:true after user confirms
71
+ - ALWAYS use request_user_confirmation to get user approval before creating skills never create skills without approval
72
72
  - Use job_run to start a job — it gives you the job's goal and available skills as capabilities
73
73
  - When running a job, be AGENTIC: decide dynamically what to do based on what you discover
74
74
  - Do NOT follow a fixed sequence — if checking Slack reveals a task that needs GitHub, go do GitHub immediately