assistme 0.3.1 → 0.3.2

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 (44) hide show
  1. package/PLAN.md +14 -3
  2. package/dist/{chunk-UWE5WVQI.js → chunk-KX7ITO55.js} +20 -11
  3. package/dist/index.js +1771 -496
  4. package/dist/{job-runner-N4XAAWLJ.js → job-runner-P2L6MOOX.js} +1 -1
  5. package/package.json +5 -3
  6. package/src/agent/job-runner.ts +9 -13
  7. package/src/agent/mcp-servers.ts +6 -952
  8. package/src/agent/memory.ts +2 -11
  9. package/src/agent/processor.ts +17 -107
  10. package/src/agent/scheduler.ts +2 -3
  11. package/src/agent/session.ts +20 -36
  12. package/src/agent/skills.ts +167 -61
  13. package/src/agent/system-prompt.ts +126 -0
  14. package/src/browser/chrome-launcher.ts +555 -0
  15. package/src/browser/controller.ts +1386 -0
  16. package/src/browser/types.ts +70 -0
  17. package/src/commands/credential.ts +190 -0
  18. package/src/commands/job.ts +14 -45
  19. package/src/commands/memory.ts +16 -29
  20. package/src/commands/schedule.ts +15 -37
  21. package/src/commands/start.ts +11 -43
  22. package/src/credentials/credential-store.test.ts +162 -0
  23. package/src/credentials/credential-store.ts +266 -0
  24. package/src/credentials/encryption.test.ts +98 -0
  25. package/src/credentials/encryption.ts +82 -0
  26. package/src/credentials/index.ts +15 -0
  27. package/src/credentials/local-store.ts +89 -0
  28. package/src/db/action.ts +19 -0
  29. package/src/db/api-client.ts +3 -32
  30. package/src/db/auth-store.ts +41 -0
  31. package/src/db/auth.ts +38 -0
  32. package/src/db/conversation.ts +39 -0
  33. package/src/db/event.ts +52 -0
  34. package/src/db/job-poll.ts +18 -0
  35. package/src/db/session.ts +60 -0
  36. package/src/db/supabase.ts +40 -383
  37. package/src/db/task.ts +69 -0
  38. package/src/db/types.ts +54 -0
  39. package/src/index.ts +2 -0
  40. package/src/mcp/agent-tools-server.ts +1047 -0
  41. package/src/mcp/browser-server.ts +258 -0
  42. package/src/tools/browser.ts +28 -1208
  43. package/src/tools/index.ts +32 -263
  44. package/src/tools/web.ts +0 -73
@@ -0,0 +1,70 @@
1
+ export interface CDPTab {
2
+ id: string;
3
+ title: string;
4
+ url: string;
5
+ type: string;
6
+ webSocketDebuggerUrl?: string;
7
+ }
8
+
9
+ export interface CDPResponse {
10
+ id: number;
11
+ result?: Record<string, unknown>;
12
+ error?: { code: number; message: string };
13
+ }
14
+
15
+ /** Shape returned by Runtime.evaluate CDP calls */
16
+ export interface CDPEvalResult {
17
+ result?: { value?: unknown; description?: string };
18
+ }
19
+
20
+ /** Shape returned by Page.captureScreenshot CDP calls */
21
+ export interface CDPScreenshotResult {
22
+ data?: string;
23
+ }
24
+
25
+ // ── Ref System Types ────────────────────────────────────────────────
26
+
27
+ export interface BoundingBox {
28
+ x: number;
29
+ y: number;
30
+ width: number;
31
+ height: number;
32
+ }
33
+
34
+ export interface RefEntry {
35
+ id: number;
36
+ role: string;
37
+ name: string;
38
+ tag: string;
39
+ inputType: string;
40
+ box: BoundingBox;
41
+ }
42
+
43
+ export interface SnapshotResult {
44
+ image: string;
45
+ refs: RefEntry[];
46
+ url: string;
47
+ title: string;
48
+ }
49
+
50
+ export type ActionSpec =
51
+ | { action: "click"; ref: number }
52
+ | { action: "type"; ref: number; text: string }
53
+ | { action: "select"; ref: number; option: string }
54
+ | { action: "press"; key: string }
55
+ | { action: "scroll"; direction: "up" | "down" }
56
+ | { action: "wait"; ms: number };
57
+
58
+ export interface ActionResult {
59
+ action: string;
60
+ ref?: number;
61
+ result: string;
62
+ success: boolean;
63
+ }
64
+
65
+ export interface AutoLaunchResult {
66
+ success: boolean;
67
+ action: "already_available" | "launched" | "chrome_not_found" | "launch_failed" | "port_conflict";
68
+ chromePath?: string;
69
+ detail?: string;
70
+ }
@@ -0,0 +1,190 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import { createInterface } from "readline";
4
+ import { getCredentialStore, type CredentialType } from "../credentials/index.js";
5
+ import { log } from "../utils/logger.js";
6
+
7
+ const VALID_TYPES: CredentialType[] = ["api_key", "oauth_token", "login", "secret", "custom"];
8
+
9
+ export function registerCredentialCommands(program: Command): void {
10
+ const credCmd = program
11
+ .command("credential")
12
+ .alias("cred")
13
+ .description("Manage locally stored credentials (encrypted, never sent to server)");
14
+
15
+ credCmd
16
+ .command("list")
17
+ .description("List all stored credentials (metadata only, no secrets)")
18
+ .option("-s, --skill <name>", "Filter by skill name")
19
+ .option("-t, --type <type>", "Filter by credential type")
20
+ .action(async (opts) => {
21
+ const store = getCredentialStore();
22
+ let results = store.list();
23
+
24
+ if (opts.skill) {
25
+ results = results.filter((m) => m.skillName === opts.skill);
26
+ }
27
+ if (opts.type) {
28
+ results = results.filter((m) => m.type === opts.type);
29
+ }
30
+
31
+ if (results.length === 0) {
32
+ console.log(chalk.yellow(" No credentials stored."));
33
+ console.log(chalk.dim(" Use `assistme credential set <name>` to add one."));
34
+ return;
35
+ }
36
+
37
+ console.log(chalk.bold("\n Stored Credentials:\n"));
38
+ for (const m of results) {
39
+ const skill = m.skillName ? chalk.dim(` [${m.skillName}]`) : "";
40
+ const tags = m.tags.length > 0 ? chalk.dim(` (${m.tags.join(", ")})`) : "";
41
+ console.log(` ${chalk.cyan(m.name)} ${chalk.gray(`(${m.type})`)}${skill}${tags}`);
42
+ console.log(chalk.dim(` ID: ${m.id} Created: ${m.createdAt.slice(0, 10)}`));
43
+ }
44
+ console.log();
45
+ });
46
+
47
+ credCmd
48
+ .command("set <name>")
49
+ .description("Store or update a credential interactively")
50
+ .option("-t, --type <type>", `Credential type: ${VALID_TYPES.join(", ")}`, "secret")
51
+ .option("-s, --skill <name>", "Associate with a skill")
52
+ .option("--tags <tags>", "Comma-separated tags")
53
+ .action(async (name, opts) => {
54
+ if (!VALID_TYPES.includes(opts.type)) {
55
+ log.error(`Invalid type "${opts.type}". Must be one of: ${VALID_TYPES.join(", ")}`);
56
+ process.exit(1);
57
+ }
58
+
59
+ const rl = createInterface({
60
+ input: process.stdin,
61
+ output: process.stdout,
62
+ });
63
+
64
+ const ask = (q: string): Promise<string> =>
65
+ new Promise((resolve) => {
66
+ rl.question(q, (answer) => resolve(answer.trim()));
67
+ });
68
+
69
+ console.log(chalk.bold(`\n Set credential: ${name}`));
70
+ console.log(chalk.dim(" Enter key-value pairs. Empty key to finish.\n"));
71
+
72
+ const data: Record<string, string> = {};
73
+
74
+ // For common types, provide helpful prompts
75
+ if (opts.type === "login") {
76
+ data.username = await ask(chalk.cyan(" Username: "));
77
+ data.password = await ask(chalk.cyan(" Password: "));
78
+ } else if (opts.type === "api_key") {
79
+ data.api_key = await ask(chalk.cyan(" API Key: "));
80
+ } else {
81
+ // Generic key-value input
82
+ while (true) {
83
+ const key = await ask(chalk.cyan(" Key (empty to finish): "));
84
+ if (!key) break;
85
+ const value = await ask(chalk.cyan(` Value for "${key}": `));
86
+ data[key] = value;
87
+ }
88
+ }
89
+
90
+ rl.close();
91
+
92
+ if (Object.keys(data).length === 0) {
93
+ console.log(chalk.yellow(" No data provided. Credential not saved."));
94
+ return;
95
+ }
96
+
97
+ const store = getCredentialStore();
98
+ const tags = opts.tags ? opts.tags.split(",").map((t: string) => t.trim()) : [];
99
+ const meta = store.save(name, opts.type, data, {
100
+ skillName: opts.skill,
101
+ tags,
102
+ });
103
+
104
+ log.success(`Credential "${meta.name}" saved (ID: ${meta.id})`);
105
+ console.log(chalk.dim(" Encrypted and stored at ~/.config/assistme/credentials/"));
106
+ });
107
+
108
+ credCmd
109
+ .command("get <name>")
110
+ .description("Show credential metadata (use --reveal to show secrets)")
111
+ .option("-r, --reveal", "Reveal secret values")
112
+ .action(async (name, opts) => {
113
+ const store = getCredentialStore();
114
+ const credential = store.getByName(name);
115
+
116
+ if (!credential) {
117
+ log.error(`Credential not found: ${name}`);
118
+ process.exit(1);
119
+ }
120
+
121
+ const m = credential.meta;
122
+ console.log(chalk.bold(`\n ${m.name} (${m.type})`));
123
+ if (m.skillName) console.log(` Skill: ${m.skillName}`);
124
+ if (m.tags.length > 0) console.log(` Tags: ${m.tags.join(", ")}`);
125
+ console.log(` Created: ${m.createdAt}`);
126
+ console.log(` Updated: ${m.updatedAt}`);
127
+
128
+ if (opts.reveal) {
129
+ console.log(chalk.bold("\n Data:"));
130
+ for (const [key, value] of Object.entries(credential.data)) {
131
+ console.log(` ${chalk.cyan(key)}: ${value}`);
132
+ }
133
+ } else {
134
+ console.log(chalk.bold("\n Data keys:"));
135
+ for (const key of Object.keys(credential.data)) {
136
+ console.log(` ${chalk.cyan(key)}: ${"*".repeat(8)}`);
137
+ }
138
+ console.log(chalk.dim("\n Use --reveal to show secret values."));
139
+ }
140
+ console.log();
141
+ });
142
+
143
+ credCmd
144
+ .command("remove <name>")
145
+ .description("Remove a stored credential")
146
+ .action(async (name) => {
147
+ const store = getCredentialStore();
148
+ const removed = store.removeByName(name);
149
+ if (removed) {
150
+ log.success(`Credential "${name}" removed.`);
151
+ } else {
152
+ log.error(`Credential not found: ${name}`);
153
+ }
154
+ });
155
+
156
+ credCmd
157
+ .command("clear")
158
+ .description("Remove ALL stored credentials")
159
+ .action(async () => {
160
+ const store = getCredentialStore();
161
+ const count = store.list().length;
162
+
163
+ if (count === 0) {
164
+ console.log(chalk.yellow(" No credentials to clear."));
165
+ return;
166
+ }
167
+
168
+ const rl = createInterface({
169
+ input: process.stdin,
170
+ output: process.stdout,
171
+ });
172
+
173
+ const answer = await new Promise<string>((resolve) => {
174
+ rl.question(
175
+ chalk.red(` Remove ALL ${count} credential(s)? This cannot be undone. (yes/no): `),
176
+ (ans) => {
177
+ rl.close();
178
+ resolve(ans.trim().toLowerCase());
179
+ },
180
+ );
181
+ });
182
+
183
+ if (answer === "yes" || answer === "y") {
184
+ store.clear();
185
+ log.success(`All ${count} credential(s) removed.`);
186
+ } else {
187
+ console.log(chalk.dim(" Cancelled."));
188
+ }
189
+ });
190
+ }
@@ -3,14 +3,10 @@ import chalk from "chalk";
3
3
  import { getCurrentUserId } from "../db/supabase.js";
4
4
  import { callMcpHandler } from "../db/api-client.js";
5
5
  import { log } from "../utils/logger.js";
6
- import {
7
- createScheduledTask,
8
- } from "../agent/scheduler.js";
6
+ import { createScheduledTask } from "../agent/scheduler.js";
9
7
 
10
8
  export function registerJobCommands(program: Command): void {
11
- const jobCmd = program
12
- .command("job")
13
- .description("Manage and run automated jobs");
9
+ const jobCmd = program.command("job").description("Manage and run automated jobs");
14
10
 
15
11
  jobCmd
16
12
  .command("list")
@@ -19,22 +15,18 @@ export function registerJobCommands(program: Command): void {
19
15
  try {
20
16
  const userId = await getCurrentUserId();
21
17
  const { JobRunner } = await import("../agent/job-runner.js");
22
- const runner = new JobRunner(userId);
18
+ const runner = new JobRunner();
23
19
  const jobs = await runner.listJobs();
24
20
 
25
21
  if (jobs.length === 0) {
26
22
  console.log(chalk.yellow("No jobs defined."));
27
- console.log(
28
- 'Use "assistme" and tell the agent about your job to generate skills.'
29
- );
23
+ console.log('Use "assistme" and tell the agent about your job to generate skills.');
30
24
  return;
31
25
  }
32
26
 
33
27
  console.log(chalk.bold("\nYour Jobs:"));
34
28
  for (const job of jobs) {
35
- console.log(
36
- ` ${chalk.cyan(job.name)} (${job.skillCount} skills)`
37
- );
29
+ console.log(` ${chalk.cyan(job.name)} (${job.skillCount} skills)`);
38
30
  console.log(
39
31
  ` ${job.description.slice(0, 80)}${job.description.length > 80 ? "..." : ""}`
40
32
  );
@@ -54,26 +46,15 @@ export function registerJobCommands(program: Command): void {
54
46
  try {
55
47
  const userId = await getCurrentUserId();
56
48
  const { JobRunner } = await import("../agent/job-runner.js");
57
- const runner = new JobRunner(userId);
58
- const runs = await runner.getRunHistory(
59
- name,
60
- parseInt(opts.limit || "5")
61
- );
49
+ const runner = new JobRunner();
50
+ const runs = await runner.getRunHistory(name, parseInt(opts.limit || "5"));
62
51
 
63
52
  if (runs.length === 0) {
64
- console.log(
65
- chalk.yellow(
66
- name ? `No runs found for "${name}".` : "No job runs yet."
67
- )
68
- );
53
+ console.log(chalk.yellow(name ? `No runs found for "${name}".` : "No job runs yet."));
69
54
  return;
70
55
  }
71
56
 
72
- console.log(
73
- chalk.bold(
74
- `\nJob Run History${name ? ` — ${name}` : ""}:`
75
- )
76
- );
57
+ console.log(chalk.bold(`\nJob Run History${name ? ` — ${name}` : ""}:`));
77
58
  for (const run of runs) {
78
59
  const icon =
79
60
  run.status === "completed"
@@ -88,14 +69,10 @@ export function registerJobCommands(program: Command): void {
88
69
  ? `${Math.round((new Date(run.completedAt).getTime() - new Date(run.startedAt).getTime()) / 1000)}s`
89
70
  : "in progress";
90
71
 
91
- console.log(
92
- ` ${icon} ${chalk.bold(run.jobName)} | ${run.triggerType} | ${date}`
93
- );
72
+ console.log(` ${icon} ${chalk.bold(run.jobName)} | ${run.triggerType} | ${date}`);
94
73
  console.log(` Duration: ${duration}`);
95
74
  if (run.summary) {
96
- console.log(
97
- ` ${chalk.dim(run.summary.slice(0, 100))}`
98
- );
75
+ console.log(` ${chalk.dim(run.summary.slice(0, 100))}`);
99
76
  }
100
77
  console.log();
101
78
  }
@@ -126,29 +103,21 @@ export function registerJobCommands(program: Command): void {
126
103
  }
127
104
  const userId = await getCurrentUserId();
128
105
  const { JobRunner } = await import("../agent/job-runner.js");
129
- const runner = new JobRunner(userId);
106
+ const runner = new JobRunner();
130
107
  const job = await runner.loadJob(name);
131
108
 
132
109
  if (!job) {
133
110
  log.error(`Job "${name}" not found.`);
134
111
  const jobs = await runner.listJobs();
135
112
  if (jobs.length > 0) {
136
- console.log(
137
- `Available: ${jobs.map((j) => j.name).join(", ")}`
138
- );
113
+ console.log(`Available: ${jobs.map((j) => j.name).join(", ")}`);
139
114
  }
140
115
  process.exit(1);
141
116
  }
142
117
 
143
118
  const tz = opts.timezone || "UTC";
144
119
  const prompt = `[JobRun: ${name}] Run the "${name}" job. Use job_run to execute it.`;
145
- const task = await createScheduledTask(
146
- userId,
147
- `Job: ${name}`,
148
- prompt,
149
- opts.cron,
150
- tz
151
- );
120
+ const task = await createScheduledTask(`Job: ${name}`, prompt, opts.cron, tz);
152
121
 
153
122
  // Link job_id
154
123
  await callMcpHandler("schedule.link_job", {
@@ -5,9 +5,7 @@ import { log } from "../utils/logger.js";
5
5
  import { MemoryManager } from "../agent/memory.js";
6
6
 
7
7
  export function registerMemoryCommands(program: Command): void {
8
- const memoryCmd = program
9
- .command("memory")
10
- .description("Manage the agent's memory about you");
8
+ const memoryCmd = program.command("memory").description("Manage the agent's memory about you");
11
9
 
12
10
  memoryCmd
13
11
  .command("list")
@@ -16,18 +14,13 @@ export function registerMemoryCommands(program: Command): void {
16
14
  .option("-l, --limit <number>", "Max items (default: 20)")
17
15
  .action(async (opts) => {
18
16
  try {
19
- const userId = await getCurrentUserId();
20
- const mm = new MemoryManager(userId);
21
- const memories = await mm.list(
22
- opts.category,
23
- parseInt(opts.limit || "20")
24
- );
17
+ await getCurrentUserId();
18
+ const mm = new MemoryManager();
19
+ const memories = await mm.list(opts.category, parseInt(opts.limit || "20"));
25
20
 
26
21
  if (memories.length === 0) {
27
22
  console.log(chalk.yellow("No memories stored yet."));
28
- console.log(
29
- "The agent will automatically remember things as you interact with it."
30
- );
23
+ console.log("The agent will automatically remember things as you interact with it.");
31
24
  return;
32
25
  }
33
26
 
@@ -66,20 +59,16 @@ export function registerMemoryCommands(program: Command): void {
66
59
  .option("-t, --tags <tags>", "Comma-separated tags")
67
60
  .action(async (content, opts) => {
68
61
  try {
69
- const userId = await getCurrentUserId();
70
- const mm = new MemoryManager(userId);
71
- const tags = opts.tags
72
- ? opts.tags.split(",").map((t: string) => t.trim())
73
- : [];
62
+ await getCurrentUserId();
63
+ const mm = new MemoryManager();
64
+ const tags = opts.tags ? opts.tags.split(",").map((t: string) => t.trim()) : [];
74
65
  const mem = await mm.add(
75
66
  content,
76
67
  opts.category || "general",
77
68
  parseInt(opts.importance || "5"),
78
69
  tags
79
70
  );
80
- log.success(
81
- `Memory stored: "${mem.content.slice(0, 60)}..." [${mem.category}]`
82
- );
71
+ log.success(`Memory stored: "${mem.content.slice(0, 60)}..." [${mem.category}]`);
83
72
  } catch (err) {
84
73
  log.error(`${err instanceof Error ? err.message : err}`);
85
74
  process.exit(1);
@@ -91,8 +80,8 @@ export function registerMemoryCommands(program: Command): void {
91
80
  .description("Search memories")
92
81
  .action(async (query) => {
93
82
  try {
94
- const userId = await getCurrentUserId();
95
- const mm = new MemoryManager(userId);
83
+ await getCurrentUserId();
84
+ const mm = new MemoryManager();
96
85
  const results = await mm.search(query);
97
86
 
98
87
  if (results.length === 0) {
@@ -116,8 +105,8 @@ export function registerMemoryCommands(program: Command): void {
116
105
  .description("Delete a specific memory")
117
106
  .action(async (id) => {
118
107
  try {
119
- const userId = await getCurrentUserId();
120
- const mm = new MemoryManager(userId);
108
+ await getCurrentUserId();
109
+ const mm = new MemoryManager();
121
110
  const memories = await mm.list();
122
111
  const mem = memories.find((m) => m.id.startsWith(id));
123
112
  if (!mem) {
@@ -138,12 +127,10 @@ export function registerMemoryCommands(program: Command): void {
138
127
  .option("-c, --category <category>", "Only clear specific category")
139
128
  .action(async (opts) => {
140
129
  try {
141
- const userId = await getCurrentUserId();
142
- const mm = new MemoryManager(userId);
130
+ await getCurrentUserId();
131
+ const mm = new MemoryManager();
143
132
  await mm.clear(opts.category);
144
- log.success(
145
- `Memories cleared${opts.category ? ` (${opts.category})` : ""}`
146
- );
133
+ log.success(`Memories cleared${opts.category ? ` (${opts.category})` : ""}`);
147
134
  } catch (err) {
148
135
  log.error(`${err instanceof Error ? err.message : err}`);
149
136
  process.exit(1);
@@ -10,22 +10,14 @@ import {
10
10
  } from "../agent/scheduler.js";
11
11
 
12
12
  export function registerScheduleCommands(program: Command): void {
13
- const scheduleCmd = program
14
- .command("schedule")
15
- .description("Manage scheduled (cron) tasks");
13
+ const scheduleCmd = program.command("schedule").description("Manage scheduled (cron) tasks");
16
14
 
17
15
  scheduleCmd
18
16
  .command("add")
19
17
  .description("Add a scheduled task")
20
18
  .requiredOption("-n, --name <name>", "Task name")
21
- .requiredOption(
22
- "-p, --prompt <prompt>",
23
- "Task prompt (what the AI should do)"
24
- )
25
- .requiredOption(
26
- "-c, --cron <expression>",
27
- "Cron expression (e.g. '0 8 * * *' for daily 8am)"
28
- )
19
+ .requiredOption("-p, --prompt <prompt>", "Task prompt (what the AI should do)")
20
+ .requiredOption("-c, --cron <expression>", "Cron expression (e.g. '0 8 * * *' for daily 8am)")
29
21
  .option("-t, --timezone <tz>", "Timezone (default: UTC)")
30
22
  .action(async (opts) => {
31
23
  try {
@@ -38,14 +30,8 @@ export function registerScheduleCommands(program: Command): void {
38
30
  console.log(' Examples: "0 9 * * *" (daily 9am), "*/15 * * * *" (every 15 min)');
39
31
  process.exit(1);
40
32
  }
41
- const userId = await getCurrentUserId();
42
- const task = await createScheduledTask(
43
- userId,
44
- opts.name,
45
- opts.prompt,
46
- opts.cron,
47
- opts.timezone
48
- );
33
+ await getCurrentUserId();
34
+ const task = await createScheduledTask(opts.name, opts.prompt, opts.cron, opts.timezone);
49
35
  log.success(`Scheduled task created: ${task.name}`);
50
36
  console.log(` ID: ${task.id.slice(0, 8)}...`);
51
37
  console.log(` Cron: ${task.cron_expression}`);
@@ -63,8 +49,8 @@ export function registerScheduleCommands(program: Command): void {
63
49
  .description("List all scheduled tasks")
64
50
  .action(async () => {
65
51
  try {
66
- const userId = await getCurrentUserId();
67
- const tasks = await listScheduledTasks(userId);
52
+ await getCurrentUserId();
53
+ const tasks = await listScheduledTasks();
68
54
 
69
55
  if (tasks.length === 0) {
70
56
  console.log(chalk.yellow("No scheduled tasks."));
@@ -76,22 +62,14 @@ export function registerScheduleCommands(program: Command): void {
76
62
  for (const t of tasks) {
77
63
  const icon = t.enabled ? chalk.green("●") : chalk.dim("○");
78
64
  console.log(` ${icon} ${t.name} (${t.id.slice(0, 8)}...)`);
79
- console.log(
80
- ` Cron: ${t.cron_expression} (${t.timezone})`
81
- );
82
- console.log(
83
- ` Prompt: ${t.prompt.slice(0, 60)}${t.prompt.length > 60 ? "..." : ""}`
84
- );
65
+ console.log(` Cron: ${t.cron_expression} (${t.timezone})`);
66
+ console.log(` Prompt: ${t.prompt.slice(0, 60)}${t.prompt.length > 60 ? "..." : ""}`);
85
67
  console.log(` Runs: ${t.run_count}`);
86
68
  if (t.next_run_at) {
87
- console.log(
88
- ` Next run: ${new Date(t.next_run_at).toLocaleString()}`
89
- );
69
+ console.log(` Next run: ${new Date(t.next_run_at).toLocaleString()}`);
90
70
  }
91
71
  if (t.last_error) {
92
- console.log(
93
- chalk.red(` Error: ${t.last_error.slice(0, 80)}`)
94
- );
72
+ console.log(chalk.red(` Error: ${t.last_error.slice(0, 80)}`));
95
73
  }
96
74
  console.log();
97
75
  }
@@ -106,8 +84,8 @@ export function registerScheduleCommands(program: Command): void {
106
84
  .description("Enable/disable a scheduled task")
107
85
  .action(async (id) => {
108
86
  try {
109
- const userId = await getCurrentUserId();
110
- const tasks = await listScheduledTasks(userId);
87
+ await getCurrentUserId();
88
+ const tasks = await listScheduledTasks();
111
89
  const task = tasks.find((t) => t.id.startsWith(id));
112
90
  if (!task) {
113
91
  log.error(`Task not found: ${id}`);
@@ -126,8 +104,8 @@ export function registerScheduleCommands(program: Command): void {
126
104
  .description("Delete a scheduled task")
127
105
  .action(async (id) => {
128
106
  try {
129
- const userId = await getCurrentUserId();
130
- const tasks = await listScheduledTasks(userId);
107
+ await getCurrentUserId();
108
+ const tasks = await listScheduledTasks();
131
109
  const task = tasks.find((t) => t.id.startsWith(id));
132
110
  if (!task) {
133
111
  log.error(`Task not found: ${id}`);
@@ -13,20 +13,13 @@ export function registerStartCommand(program: Command): void {
13
13
  program
14
14
  .command("start", { isDefault: true, hidden: true })
15
15
  .description("Start the agent (default command)")
16
- .option(
17
- "-w, --workspace <path>",
18
- "Workspace path (default: current directory)"
19
- )
16
+ .option("-w, --workspace <path>", "Workspace path (default: current directory)")
20
17
  .option("-n, --name <name>", "Session name")
21
18
  .option("-v, --verbose", "Enable verbose/debug logging")
22
19
  .action(runAgent);
23
20
  }
24
21
 
25
- async function runAgent(opts: {
26
- workspace?: string;
27
- name?: string;
28
- verbose?: boolean;
29
- }) {
22
+ async function runAgent(opts: { workspace?: string; name?: string; verbose?: boolean }) {
30
23
  if (opts.verbose) {
31
24
  setLogLevel("debug");
32
25
  }
@@ -39,26 +32,10 @@ async function runAgent(opts: {
39
32
  }
40
33
 
41
34
  console.log();
42
- console.log(
43
- chalk.bold.cyan(
44
- " ╔══════════════════════════════════════════╗"
45
- )
46
- );
47
- console.log(
48
- chalk.bold.cyan(
49
- " ║ AssistMe CLI Agent ║"
50
- )
51
- );
52
- console.log(
53
- chalk.bold.cyan(
54
- " ║ AI that controls your real browser ║"
55
- )
56
- );
57
- console.log(
58
- chalk.bold.cyan(
59
- " ╚══════════════════════════════════════════╝"
60
- )
61
- );
35
+ console.log(chalk.bold.cyan(" ╔══════════════════════════════════════════╗"));
36
+ console.log(chalk.bold.cyan(" ║ AssistMe CLI Agent ║"));
37
+ console.log(chalk.bold.cyan(" ║ AI that controls your real browser ║"));
38
+ console.log(chalk.bold.cyan(" ╚══════════════════════════════════════════╝"));
62
39
  console.log();
63
40
 
64
41
  let userId: string;
@@ -79,9 +56,7 @@ async function runAgent(opts: {
79
56
  launchSpinner.succeed("Browser detected (CDP port 9222)");
80
57
  break;
81
58
  case "launched":
82
- launchSpinner.succeed(
83
- "Browser launched with remote debugging (debug profile)"
84
- );
59
+ launchSpinner.succeed("Browser launched with remote debugging (debug profile)");
85
60
  break;
86
61
  }
87
62
  } else {
@@ -92,10 +67,7 @@ async function runAgent(opts: {
92
67
  break;
93
68
  case "port_conflict":
94
69
  launchSpinner.fail("Port 9222 is in use by another process");
95
- log.info(
96
- launchResult.detail ??
97
- "Stop the conflicting process or use a different port."
98
- );
70
+ log.info(launchResult.detail ?? "Stop the conflicting process or use a different port.");
99
71
  break;
100
72
  default:
101
73
  launchSpinner.fail("Failed to start Chrome with remote debugging");
@@ -105,15 +77,13 @@ async function runAgent(opts: {
105
77
  if (launchResult.chromePath) {
106
78
  log.info(`Chrome binary: ${launchResult.chromePath}`);
107
79
  }
108
- log.info(
109
- "Browser will be auto-launched when the first task needs it."
110
- );
80
+ log.info("Browser will be auto-launched when the first task needs it.");
111
81
  break;
112
82
  }
113
83
  }
114
84
 
115
85
  const processor = new TaskProcessor();
116
- processor.setUserId(userId);
86
+ processor.init(userId);
117
87
  const sessionManager = new SessionManager();
118
88
 
119
89
  // Graceful shutdown
@@ -191,9 +161,7 @@ async function runAgent(opts: {
191
161
 
192
162
  rl.on("close", shutdown);
193
163
  } catch (err) {
194
- log.error(
195
- `Failed to start: ${err instanceof Error ? err.message : err}`
196
- );
164
+ log.error(`Failed to start: ${err instanceof Error ? err.message : err}`);
197
165
  process.exit(1);
198
166
  }
199
167
  }