assistme 0.4.0 → 0.6.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/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  AppError,
4
4
  BrowseSkillRowSchema,
5
5
  CDP_COMMAND_TIMEOUT_MS,
6
+ EDSGER_PRODUCT_SLUG,
6
7
  FRAME_CONTEXTS_MAX_SIZE,
7
8
  JobRunner,
8
9
  MAX_BUDGET_USD,
@@ -20,10 +21,16 @@ import {
20
21
  MEMORY_COMPRESSION_THRESHOLD,
21
22
  MEMORY_DEDUP_SIMILARITY_THRESHOLD,
22
23
  SCHEDULER_INTERVAL_MS,
24
+ SELF_ANALYSIS_EVENT_CONTEXT_CHARS,
25
+ SELF_ANALYSIS_LOG_CONTEXT_CHARS,
26
+ SELF_ANALYSIS_MAX_CONVERSATION_MESSAGES,
27
+ SELF_ANALYSIS_MAX_MESSAGE_EVENTS,
28
+ SELF_ANALYSIS_MAX_SESSION_LOGS,
23
29
  SHELL_MAX_OUTPUT,
24
30
  SHELL_TIMEOUT_MS,
25
31
  SKILL_DESCRIPTION_BUDGET_CHARS,
26
32
  SKILL_VALIDATION_MAX_TURNS,
33
+ SelfAnalysisResultSchema,
27
34
  SkillCreateResultSchema,
28
35
  SkillDecisionSchema,
29
36
  SkillRowSchema,
@@ -35,9 +42,10 @@ import {
35
42
  readAuthStore,
36
43
  safeParse,
37
44
  setCorrelationId,
45
+ setLogHook,
38
46
  setLogLevel,
39
47
  writeAuthStore
40
- } from "./chunk-4SBIN27G.js";
48
+ } from "./chunk-ECEOBNDM.js";
41
49
  import {
42
50
  clearConfig,
43
51
  getConfig,
@@ -2711,7 +2719,7 @@ var SessionManager = class {
2711
2719
 
2712
2720
  // src/agent/processor.ts
2713
2721
  import {
2714
- query as query2
2722
+ query as query3
2715
2723
  } from "@anthropic-ai/claude-agent-sdk";
2716
2724
 
2717
2725
  // src/agent/memory.ts
@@ -2736,10 +2744,10 @@ var MemoryManager = class {
2736
2744
  /**
2737
2745
  * Search memories by query text. Uses ILIKE + tag containment.
2738
2746
  */
2739
- async search(query3, limit = 10) {
2747
+ async search(query4, limit = 10) {
2740
2748
  try {
2741
2749
  return await callMcpHandler("memory.search", {
2742
- query: query3,
2750
+ query: query4,
2743
2751
  limit
2744
2752
  });
2745
2753
  } catch (err) {
@@ -3384,11 +3392,11 @@ _(${skills.length - included} additional skills available \u2014 use skill_searc
3384
3392
  log.debug(`Invocation log error: ${err}`);
3385
3393
  }
3386
3394
  }
3387
- async searchDb(query3, limit = 10) {
3395
+ async searchDb(query4, limit = 10) {
3388
3396
  if (this.userId) {
3389
3397
  try {
3390
3398
  const data = await callMcpHandler("skill.search", {
3391
- query: query3,
3399
+ query: query4,
3392
3400
  limit
3393
3401
  });
3394
3402
  if (data) {
@@ -3403,7 +3411,7 @@ _(${skills.length - included} additional skills available \u2014 use skill_searc
3403
3411
  } catch {
3404
3412
  }
3405
3413
  }
3406
- const results = this.findRelevant(query3, limit);
3414
+ const results = this.findRelevant(query4, limit);
3407
3415
  return results.map((s) => ({
3408
3416
  name: s.name,
3409
3417
  description: s.description,
@@ -3783,6 +3791,386 @@ async function executeSkillDecision(decision, skillManager, sessionId, model) {
3783
3791
  }
3784
3792
  }
3785
3793
 
3794
+ // src/agent/self-analyzer.ts
3795
+ import {
3796
+ query as query2
3797
+ } from "@anthropic-ai/claude-agent-sdk";
3798
+ import { submitFeedback, FeedbackError } from "edsger-feedback";
3799
+
3800
+ // src/db/analysis-data.ts
3801
+ async function getSessionLogs(sessionId, limit = 500) {
3802
+ try {
3803
+ const data = await callMcpHandler("log.list", {
3804
+ session_id: sessionId,
3805
+ limit
3806
+ });
3807
+ return data || [];
3808
+ } catch (err) {
3809
+ log.debug(`Failed to fetch session logs: ${err instanceof Error ? err.message : err}`);
3810
+ return [];
3811
+ }
3812
+ }
3813
+ async function getMessageEvents(messageId, limit = 500) {
3814
+ try {
3815
+ const data = await callMcpHandler("event.list", {
3816
+ message_id: messageId,
3817
+ limit
3818
+ });
3819
+ return data || [];
3820
+ } catch (err) {
3821
+ log.debug(`Failed to fetch message events: ${err instanceof Error ? err.message : err}`);
3822
+ return [];
3823
+ }
3824
+ }
3825
+ async function getConversationMessages(conversationId, limit = 10) {
3826
+ try {
3827
+ const data = await callMcpHandler(
3828
+ "conversation.list_messages",
3829
+ {
3830
+ conversation_id: conversationId,
3831
+ limit
3832
+ }
3833
+ );
3834
+ return data || [];
3835
+ } catch (err) {
3836
+ log.debug(`Failed to fetch conversation messages: ${err instanceof Error ? err.message : err}`);
3837
+ return [];
3838
+ }
3839
+ }
3840
+
3841
+ // src/agent/self-analyzer.ts
3842
+ var SELF_ANALYSIS_OUTPUT_FORMAT = {
3843
+ type: "json_schema",
3844
+ schema: {
3845
+ type: "object",
3846
+ properties: {
3847
+ is_perfect: { type: "boolean" },
3848
+ overall_score: { type: "number" },
3849
+ task_completion_quality: {
3850
+ type: "object",
3851
+ properties: {
3852
+ score: { type: "number" },
3853
+ assessment: { type: "string" }
3854
+ },
3855
+ required: ["score", "assessment"]
3856
+ },
3857
+ improvements: {
3858
+ type: "array",
3859
+ items: {
3860
+ type: "object",
3861
+ properties: {
3862
+ area: { type: "string" },
3863
+ severity: {
3864
+ type: "string",
3865
+ enum: ["critical", "major", "minor", "suggestion"]
3866
+ },
3867
+ description: { type: "string" },
3868
+ suggestion: { type: "string" }
3869
+ },
3870
+ required: ["area", "severity", "description", "suggestion"]
3871
+ }
3872
+ },
3873
+ data_quality: {
3874
+ type: "object",
3875
+ properties: {
3876
+ session_logs_useful: { type: "boolean" },
3877
+ session_logs_gaps: { type: "string" },
3878
+ message_events_useful: { type: "boolean" },
3879
+ message_events_gaps: { type: "string" },
3880
+ conversation_context_useful: { type: "boolean" },
3881
+ conversation_context_gaps: { type: "string" }
3882
+ },
3883
+ required: [
3884
+ "session_logs_useful",
3885
+ "message_events_useful",
3886
+ "conversation_context_useful"
3887
+ ]
3888
+ },
3889
+ summary: { type: "string" }
3890
+ },
3891
+ required: [
3892
+ "is_perfect",
3893
+ "overall_score",
3894
+ "task_completion_quality",
3895
+ "improvements",
3896
+ "data_quality",
3897
+ "summary"
3898
+ ]
3899
+ }
3900
+ };
3901
+ var SELF_ANALYSIS_PROMPT = `You just completed a task as the AssistMe agent. Now critically analyze AssistMe's own implementation \u2014 NOT the user's task itself, but how well AssistMe (the agent system) performed and whether AssistMe's codebase can be improved.
3902
+
3903
+ ## Your Role
3904
+ You are a perfectionist code reviewer analyzing the AssistMe agent system itself. Be critical, thorough, and constructive. Focus on:
3905
+
3906
+ 1. **Task Completion Quality**: Did AssistMe handle the task optimally? Were there unnecessary steps, missed edge cases, or suboptimal tool usage?
3907
+ 2. **Agent Architecture**: Based on what you observed during execution, are there architectural improvements to AssistMe's code (processor, event hooks, MCP servers, skill system, etc.)?
3908
+ 3. **Data & Observability**: Evaluate the quality of the context data provided (session logs, message events, conversation messages). What information is missing that would help diagnose issues or improve the system?
3909
+ 4. **Error Handling & Resilience**: Were there any failures or retries? Could the error handling be improved?
3910
+ 5. **Performance & Efficiency**: Were there unnecessary API calls, redundant operations, or opportunities to optimize?
3911
+ 6. **User Experience**: Could the interaction flow be smoother? Is the feedback to the user adequate?
3912
+
3913
+ ## Context Data Provided
3914
+ Below you will find:
3915
+ - **Session Logs**: stdout/stderr/status logs from the agent session
3916
+ - **Message Events**: Real-time events emitted during task execution (tool calls, results, status changes, thinking blocks)
3917
+ - **Conversation Messages**: User interaction history for this conversation
3918
+ - **Tool Call Records**: Summary of all tool calls made during the task
3919
+ - **Tool Failures**: Any tool calls that failed during execution
3920
+
3921
+ ## Instructions
3922
+ Analyze all provided data critically. Consider:
3923
+ - Are the session logs capturing enough detail for debugging?
3924
+ - Do the message events provide sufficient visibility into the agent's decision-making?
3925
+ - Is the conversation context giving enough user intent signal?
3926
+ - Were tools used efficiently?
3927
+ - Could the overall execution flow be improved?
3928
+
3929
+ Set is_perfect to true ONLY if there are genuinely zero improvements to suggest (this should be rare).
3930
+ The overall_score should be 1-10 where 10 means absolutely perfect.
3931
+
3932
+ Respond with a JSON object now.`;
3933
+ function truncateToChars(text, maxChars) {
3934
+ if (text.length <= maxChars) return text;
3935
+ return text.slice(0, maxChars) + "\n... [truncated]";
3936
+ }
3937
+ var EVENT_RESULT_SUMMARY_CHARS = 150;
3938
+ function filterAndAggregateEvents(events) {
3939
+ const lines = [];
3940
+ let pendingTextChunks = [];
3941
+ const flushTextDelta = () => {
3942
+ if (pendingTextChunks.length > 0) {
3943
+ const merged = pendingTextChunks.join("");
3944
+ const summary = merged.length > 200 ? merged.slice(0, 200) + "..." : merged;
3945
+ lines.push(`[text_delta x${pendingTextChunks.length}] ${summary}`);
3946
+ pendingTextChunks = [];
3947
+ }
3948
+ };
3949
+ for (const e of events) {
3950
+ switch (e.event_type) {
3951
+ case "text_delta": {
3952
+ const text = e.event_data.text || "";
3953
+ pendingTextChunks.push(text);
3954
+ break;
3955
+ }
3956
+ case "thinking":
3957
+ flushTextDelta();
3958
+ break;
3959
+ case "tool_use_input":
3960
+ flushTextDelta();
3961
+ break;
3962
+ case "tool_result": {
3963
+ flushTextDelta();
3964
+ const name = e.event_data.name || "unknown";
3965
+ const result = (e.event_data.result || "").slice(0, EVENT_RESULT_SUMMARY_CHARS);
3966
+ lines.push(`[tool_result] ${name}: ${result}`);
3967
+ break;
3968
+ }
3969
+ case "tool_failure":
3970
+ case "status_change":
3971
+ case "error": {
3972
+ flushTextDelta();
3973
+ lines.push(`[${e.event_type}] ${JSON.stringify(e.event_data)}`);
3974
+ break;
3975
+ }
3976
+ default: {
3977
+ flushTextDelta();
3978
+ const dataStr = JSON.stringify(e.event_data);
3979
+ lines.push(`[${e.event_type}] ${dataStr.slice(0, 200)}`);
3980
+ break;
3981
+ }
3982
+ }
3983
+ }
3984
+ flushTextDelta();
3985
+ return lines;
3986
+ }
3987
+ async function buildAnalysisContext(ctx) {
3988
+ const [sessionLogs, messageEvents, conversationMessages] = await Promise.all([
3989
+ getSessionLogs(ctx.sessionId, SELF_ANALYSIS_MAX_SESSION_LOGS),
3990
+ getMessageEvents(ctx.taskId, SELF_ANALYSIS_MAX_MESSAGE_EVENTS),
3991
+ getConversationMessages(ctx.conversationId, SELF_ANALYSIS_MAX_CONVERSATION_MESSAGES)
3992
+ ]);
3993
+ let context = "";
3994
+ if (sessionLogs.length > 0) {
3995
+ const logText = sessionLogs.map((l) => `[${l.log_type}] ${l.message}`).join("\n");
3996
+ context += `
3997
+ ## Session Logs (${sessionLogs.length} entries)
3998
+ `;
3999
+ context += truncateToChars(logText, SELF_ANALYSIS_LOG_CONTEXT_CHARS);
4000
+ } else {
4001
+ context += "\n## Session Logs\n(No session logs available \u2014 this is itself a data gap to note)\n";
4002
+ }
4003
+ if (messageEvents.length > 0) {
4004
+ const filteredLines = filterAndAggregateEvents(messageEvents);
4005
+ const eventText = filteredLines.join("\n");
4006
+ context += `
4007
+ ## Message Events (${messageEvents.length} raw \u2192 ${filteredLines.length} aggregated)
4008
+ `;
4009
+ context += truncateToChars(eventText, SELF_ANALYSIS_EVENT_CONTEXT_CHARS);
4010
+ } else {
4011
+ context += "\n## Message Events\n(No message events available \u2014 this is itself a data gap to note)\n";
4012
+ }
4013
+ if (conversationMessages.length > 0) {
4014
+ context += `
4015
+ ## Conversation Messages (${conversationMessages.length} entries)
4016
+ `;
4017
+ for (const msg of conversationMessages) {
4018
+ const role = msg.role || "unknown";
4019
+ const content = (msg.content || "").slice(0, 500);
4020
+ const status = msg.status || "";
4021
+ context += `[${role}${status ? ` (${status})` : ""}] ${content}
4022
+ `;
4023
+ }
4024
+ } else {
4025
+ context += "\n## Conversation Messages\n(No conversation messages available)\n";
4026
+ }
4027
+ if (ctx.toolCallRecords.length > 0) {
4028
+ context += `
4029
+ ## Tool Call Records (${ctx.toolCallRecords.length} calls)
4030
+ `;
4031
+ for (const tc of ctx.toolCallRecords) {
4032
+ const inputStr = JSON.stringify(tc.input).slice(0, 200);
4033
+ context += `- ${tc.name}: ${inputStr} \u2192 ${tc.result.slice(0, 100)}
4034
+ `;
4035
+ }
4036
+ }
4037
+ if (ctx.toolFailures.length > 0) {
4038
+ context += `
4039
+ ## Tool Failures (${ctx.toolFailures.length} failures)
4040
+ `;
4041
+ for (const tf of ctx.toolFailures) {
4042
+ context += `- ${tf.toolName}: ${tf.error}
4043
+ `;
4044
+ }
4045
+ }
4046
+ if (ctx.tokenUsage) {
4047
+ context += `
4048
+ ## Token Usage
4049
+ `;
4050
+ context += `Input: ${ctx.tokenUsage.input_tokens}, Output: ${ctx.tokenUsage.output_tokens}
4051
+ `;
4052
+ }
4053
+ context += `
4054
+ ## Task
4055
+ `;
4056
+ context += `Prompt: ${ctx.taskPrompt.slice(0, 500)}
4057
+ `;
4058
+ context += `Response length: ${ctx.taskResponse.length} chars
4059
+ `;
4060
+ return context;
4061
+ }
4062
+ async function submitSelfAnalysisFeedback(analysis) {
4063
+ const title = `Self-Analysis: Score ${analysis.overall_score}/10 \u2014 ${analysis.improvements.length} improvement(s)`;
4064
+ const improvementDetails = analysis.improvements.map((imp, i) => `${i + 1}. [${imp.severity}] **${imp.area}**: ${imp.description}
4065
+ \u2192 ${imp.suggestion}`).join("\n");
4066
+ const dataQualityNotes = [
4067
+ analysis.data_quality.session_logs_gaps ? `Session logs: ${analysis.data_quality.session_logs_gaps}` : null,
4068
+ analysis.data_quality.message_events_gaps ? `Message events: ${analysis.data_quality.message_events_gaps}` : null,
4069
+ analysis.data_quality.conversation_context_gaps ? `Conversation context: ${analysis.data_quality.conversation_context_gaps}` : null
4070
+ ].filter(Boolean).join("\n");
4071
+ let description = `## Summary
4072
+ ${analysis.summary}
4073
+
4074
+ `;
4075
+ description += `## Task Completion Quality (${analysis.task_completion_quality.score}/10)
4076
+ ${analysis.task_completion_quality.assessment}
4077
+
4078
+ `;
4079
+ description += `## Improvements
4080
+ ${improvementDetails}
4081
+ `;
4082
+ if (dataQualityNotes) {
4083
+ description += `
4084
+ ## Data Quality Gaps
4085
+ ${dataQualityNotes}
4086
+ `;
4087
+ }
4088
+ if (description.length > 4900) {
4089
+ description = description.slice(0, 4900) + "\n...[truncated]";
4090
+ }
4091
+ try {
4092
+ const result = await submitFeedback({
4093
+ slug: EDSGER_PRODUCT_SLUG,
4094
+ title: title.slice(0, 200),
4095
+ description,
4096
+ category: "improvement"
4097
+ });
4098
+ log.info(`Self-analysis feedback submitted: ${result.id}`);
4099
+ } catch (err) {
4100
+ if (err instanceof FeedbackError) {
4101
+ log.debug(`Feedback submission failed (${err.statusCode}): ${err.message}`);
4102
+ } else {
4103
+ log.debug(`Feedback submission failed: ${errorMessage(err)}`);
4104
+ }
4105
+ }
4106
+ }
4107
+ async function analyzeSelfPostTask(opts) {
4108
+ const {
4109
+ model,
4110
+ taskId,
4111
+ conversationId,
4112
+ taskPrompt,
4113
+ taskResponse,
4114
+ toolCallRecords,
4115
+ toolFailures,
4116
+ tokenUsage,
4117
+ sessionId
4118
+ } = opts;
4119
+ try {
4120
+ const analysisContext = await buildAnalysisContext({
4121
+ taskId,
4122
+ conversationId,
4123
+ sessionId,
4124
+ taskPrompt,
4125
+ taskResponse,
4126
+ toolCallRecords,
4127
+ toolFailures,
4128
+ tokenUsage
4129
+ });
4130
+ const prompt = `${SELF_ANALYSIS_PROMPT}
4131
+ ${analysisContext}
4132
+
4133
+ Respond with a JSON object now.`;
4134
+ let structuredOutput;
4135
+ for await (const message of query2({
4136
+ prompt,
4137
+ options: {
4138
+ model,
4139
+ maxTurns: 1,
4140
+ allowedTools: [],
4141
+ effort: "low",
4142
+ outputFormat: SELF_ANALYSIS_OUTPUT_FORMAT
4143
+ }
4144
+ })) {
4145
+ if (message.type === "result") {
4146
+ const resultMsg = message;
4147
+ if (resultMsg.subtype === "success") {
4148
+ const successMsg = resultMsg;
4149
+ structuredOutput = successMsg.structured_output;
4150
+ log.debug(
4151
+ `Self-analysis cost: $${successMsg.total_cost_usd.toFixed(4)}`
4152
+ );
4153
+ }
4154
+ }
4155
+ }
4156
+ const analysis = structuredOutput ? safeParse(SelfAnalysisResultSchema, structuredOutput) : null;
4157
+ if (!analysis) {
4158
+ log.debug("Self-analysis: no valid structured output");
4159
+ return;
4160
+ }
4161
+ log.info(
4162
+ `Self-analysis complete: score=${analysis.overall_score}/10, perfect=${analysis.is_perfect}, improvements=${analysis.improvements.length}`
4163
+ );
4164
+ if (!analysis.is_perfect && analysis.improvements.length > 0) {
4165
+ await submitSelfAnalysisFeedback(analysis);
4166
+ } else {
4167
+ log.debug("Self-analysis: no improvements to report \u2014 skipping feedback");
4168
+ }
4169
+ } catch (err) {
4170
+ log.debug(`Self-analysis error: ${errorMessage(err)}`);
4171
+ }
4172
+ }
4173
+
3786
4174
  // src/utils/retry.ts
3787
4175
  async function withRetry(fn, opts = {}) {
3788
4176
  const {
@@ -6021,7 +6409,7 @@ var TaskProcessor = class {
6021
6409
  maxBudgetUsd: MAX_BUDGET_USD
6022
6410
  };
6023
6411
  try {
6024
- for await (const message of query2({ prompt: task.prompt, options })) {
6412
+ for await (const message of query3({ prompt: task.prompt, options })) {
6025
6413
  switch (message.type) {
6026
6414
  case "assistant": {
6027
6415
  const assistantMsg = message;
@@ -6096,9 +6484,29 @@ var TaskProcessor = class {
6096
6484
  );
6097
6485
  }
6098
6486
  if (agentSessionId) {
6099
- this.evaluateSkillPostTask(agentSessionId, config.model).catch(
6100
- (err) => log.debug(`Post-task skill evaluation skipped: ${err}`)
6101
- );
6487
+ (async () => {
6488
+ try {
6489
+ await this.evaluateSkillPostTask(agentSessionId, config.model);
6490
+ } catch (err) {
6491
+ log.debug(`Post-task skill evaluation skipped: ${err}`);
6492
+ }
6493
+ try {
6494
+ await analyzeSelfPostTask({
6495
+ model: config.model,
6496
+ taskId: task.id,
6497
+ conversationId: task.conversation_id,
6498
+ taskPrompt: task.prompt,
6499
+ taskResponse: finalResponse,
6500
+ toolCallRecords,
6501
+ toolFailures,
6502
+ tokenUsage,
6503
+ sessionId: this.sessionId || ""
6504
+ });
6505
+ } catch (err) {
6506
+ log.debug(`Post-task self-analysis skipped: ${err}`);
6507
+ }
6508
+ })().catch(() => {
6509
+ });
6102
6510
  }
6103
6511
  } catch (err) {
6104
6512
  const errMsg = errorMessage(err);
@@ -6119,6 +6527,57 @@ var TaskProcessor = class {
6119
6527
  }
6120
6528
  };
6121
6529
 
6530
+ // src/db/session-log.ts
6531
+ var FLUSH_INTERVAL_MS = 3e3;
6532
+ var MAX_BATCH_SIZE = 100;
6533
+ var SessionLogEmitter = class {
6534
+ constructor(sessionId) {
6535
+ this.sessionId = sessionId;
6536
+ this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
6537
+ }
6538
+ sequence = 0;
6539
+ buffer = [];
6540
+ flushTimer = null;
6541
+ flushing = false;
6542
+ /** Queue a log entry for batch insertion */
6543
+ push(logType, message) {
6544
+ this.sequence++;
6545
+ this.buffer.push({ log_type: logType, message, seq: this.sequence });
6546
+ if (this.buffer.length >= MAX_BATCH_SIZE) {
6547
+ this.flush();
6548
+ }
6549
+ }
6550
+ /** Flush buffered logs to Supabase */
6551
+ async flush() {
6552
+ if (this.flushing || this.buffer.length === 0) return;
6553
+ const batch = this.buffer.splice(0);
6554
+ this.flushing = true;
6555
+ try {
6556
+ await callMcpHandler("log.emit_batch", {
6557
+ session_id: this.sessionId,
6558
+ logs: batch
6559
+ });
6560
+ } catch (err) {
6561
+ log.debug(
6562
+ `Failed to flush session logs: ${err instanceof Error ? err.message : err}`
6563
+ );
6564
+ if (this.buffer.length < MAX_BATCH_SIZE * 5) {
6565
+ this.buffer.unshift(...batch);
6566
+ }
6567
+ } finally {
6568
+ this.flushing = false;
6569
+ }
6570
+ }
6571
+ /** Stop the emitter and flush remaining logs */
6572
+ async stop() {
6573
+ if (this.flushTimer) {
6574
+ clearInterval(this.flushTimer);
6575
+ this.flushTimer = null;
6576
+ }
6577
+ await this.flush();
6578
+ }
6579
+ };
6580
+
6122
6581
  // src/commands/start.ts
6123
6582
  function registerStartCommand(program2) {
6124
6583
  program2.command("start", { isDefault: true, hidden: true }).description("Start the agent (default command)").option("-w, --workspace <path>", "Workspace path (default: current directory)").option("-n, --name <name>", "Session name").option("-v, --verbose", "Enable verbose/debug logging").action(runAgent);
@@ -6182,10 +6641,16 @@ async function runAgent(opts) {
6182
6641
  const processor = new TaskProcessor();
6183
6642
  processor.init(userId);
6184
6643
  const sessionManager = new SessionManager();
6644
+ let logEmitter = null;
6185
6645
  const browserRef = getBrowser();
6186
6646
  const shutdown = async () => {
6187
6647
  console.log();
6188
6648
  log.info("Shutting down...");
6649
+ setLogHook(null);
6650
+ try {
6651
+ if (logEmitter) await logEmitter.stop();
6652
+ } catch {
6653
+ }
6189
6654
  try {
6190
6655
  if (browserRef.isConnected()) await browserRef.disconnect();
6191
6656
  } catch {
@@ -6200,6 +6665,10 @@ async function runAgent(opts) {
6200
6665
  await processor.processTask(task);
6201
6666
  });
6202
6667
  processor.setSessionId(session.id);
6668
+ logEmitter = new SessionLogEmitter(session.id);
6669
+ setLogHook((logType, message) => {
6670
+ logEmitter?.push(logType, message);
6671
+ });
6203
6672
  log.info("Listening for tasks (chat + jobs) from web UI...");
6204
6673
  log.info("Press Ctrl+C to stop.\n");
6205
6674
  const rl = createInterface2({
@@ -6425,17 +6894,17 @@ Memories (${memories.length}):`));
6425
6894
  process.exit(1);
6426
6895
  }
6427
6896
  });
6428
- memoryCmd.command("search <query>").description("Search memories").action(async (query3) => {
6897
+ memoryCmd.command("search <query>").description("Search memories").action(async (query4) => {
6429
6898
  try {
6430
6899
  await getCurrentUserId();
6431
6900
  const mm = new MemoryManager();
6432
- const results = await mm.search(query3);
6901
+ const results = await mm.search(query4);
6433
6902
  if (results.length === 0) {
6434
- console.log(chalk7.yellow(`No memories matching "${query3}"`));
6903
+ console.log(chalk7.yellow(`No memories matching "${query4}"`));
6435
6904
  return;
6436
6905
  }
6437
6906
  console.log(chalk7.bold(`
6438
- Search results for "${query3}":`));
6907
+ Search results for "${query4}":`));
6439
6908
  for (const m of results) {
6440
6909
  console.log(` [${m.category}] ${m.content}`);
6441
6910
  }
@@ -6501,18 +6970,18 @@ function registerSkillCommands(program2) {
6501
6970
  );
6502
6971
  console.log();
6503
6972
  });
6504
- skillCmd.command("search <query>").description("Search skills in your collection and marketplace").action(async (query3) => {
6973
+ skillCmd.command("search <query>").description("Search skills in your collection and marketplace").action(async (query4) => {
6505
6974
  const spinner = ora4("Searching skills...").start();
6506
6975
  const sm = await getAuthenticatedSkillManager();
6507
6976
  try {
6508
- const results = await sm.searchDb(query3);
6977
+ const results = await sm.searchDb(query4);
6509
6978
  spinner.stop();
6510
6979
  if (results.length === 0) {
6511
- console.log(chalk8.yellow(`No skills found for "${query3}"`));
6980
+ console.log(chalk8.yellow(`No skills found for "${query4}"`));
6512
6981
  return;
6513
6982
  }
6514
6983
  console.log(chalk8.bold(`
6515
- Skills matching "${query3}":`));
6984
+ Skills matching "${query4}":`));
6516
6985
  for (const r of results) {
6517
6986
  const emoji = r.emoji ? `${r.emoji} ` : "";
6518
6987
  console.log(` ${emoji}${chalk8.cyan(r.name)} [${r.source}]`);
@@ -6605,7 +7074,7 @@ function registerJobCommands(program2) {
6605
7074
  jobCmd.command("list").description("List your defined jobs").action(async () => {
6606
7075
  try {
6607
7076
  const userId = await getCurrentUserId();
6608
- const { JobRunner: JobRunner2 } = await import("./job-runner-CJ7HM4GZ.js");
7077
+ const { JobRunner: JobRunner2 } = await import("./job-runner-RGP4CLYV.js");
6609
7078
  const runner = new JobRunner2();
6610
7079
  const jobs = await runner.listJobs();
6611
7080
  if (jobs.length === 0) {
@@ -6629,7 +7098,7 @@ function registerJobCommands(program2) {
6629
7098
  jobCmd.command("status [name]").description("Show run history for a job (or all jobs)").option("-l, --limit <number>", "Max runs to show (default: 5)").action(async (name, opts) => {
6630
7099
  try {
6631
7100
  const userId = await getCurrentUserId();
6632
- const { JobRunner: JobRunner2 } = await import("./job-runner-CJ7HM4GZ.js");
7101
+ const { JobRunner: JobRunner2 } = await import("./job-runner-RGP4CLYV.js");
6633
7102
  const runner = new JobRunner2();
6634
7103
  const runs = await runner.getRunHistory(name, parseInt(opts.limit || "5"));
6635
7104
  if (runs.length === 0) {
@@ -6668,7 +7137,7 @@ Job Run History${name ? ` \u2014 ${name}` : ""}:`));
6668
7137
  process.exit(1);
6669
7138
  }
6670
7139
  const userId = await getCurrentUserId();
6671
- const { JobRunner: JobRunner2 } = await import("./job-runner-CJ7HM4GZ.js");
7140
+ const { JobRunner: JobRunner2 } = await import("./job-runner-RGP4CLYV.js");
6672
7141
  const runner = new JobRunner2();
6673
7142
  const job = await runner.loadJob(name);
6674
7143
  if (!job) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  JobRunner
3
- } from "./chunk-4SBIN27G.js";
3
+ } from "./chunk-ECEOBNDM.js";
4
4
  import "./chunk-JVA6DHXD.js";
5
5
  export {
6
6
  JobRunner
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistme",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "AssistMe CLI Agent - AI-powered assistant that controls your real browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,6 +26,7 @@
26
26
  "conf": "^13.0.1",
27
27
  "croner": "^10.0.1",
28
28
  "dotenv": "^16.5.0",
29
+ "edsger-feedback": "^0.1.0",
29
30
  "glob": "^11.0.1",
30
31
  "ora": "^8.2.0",
31
32
  "ws": "^8.18.0",