assistme 0.3.0 → 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.
- package/PLAN.md +14 -3
- package/dist/{chunk-UWE5WVQI.js → chunk-KX7ITO55.js} +20 -11
- package/dist/index.js +1791 -572
- package/dist/{job-runner-N4XAAWLJ.js → job-runner-P2L6MOOX.js} +1 -1
- package/package.json +5 -3
- package/src/agent/job-runner.ts +9 -13
- package/src/agent/mcp-servers.ts +6 -1020
- package/src/agent/memory.ts +2 -11
- package/src/agent/processor.ts +18 -108
- package/src/agent/scheduler.ts +2 -3
- package/src/agent/session.ts +20 -36
- package/src/agent/skills.ts +167 -61
- package/src/agent/system-prompt.ts +126 -0
- package/src/browser/chrome-launcher.ts +555 -0
- package/src/browser/controller.ts +1386 -0
- package/src/browser/types.ts +70 -0
- package/src/commands/credential.ts +190 -0
- package/src/commands/job.ts +14 -45
- package/src/commands/memory.ts +16 -29
- package/src/commands/schedule.ts +15 -37
- package/src/commands/start.ts +11 -43
- package/src/credentials/credential-store.test.ts +162 -0
- package/src/credentials/credential-store.ts +266 -0
- package/src/credentials/encryption.test.ts +98 -0
- package/src/credentials/encryption.ts +82 -0
- package/src/credentials/index.ts +15 -0
- package/src/credentials/local-store.ts +89 -0
- package/src/db/action.ts +19 -0
- package/src/db/api-client.ts +3 -32
- package/src/db/auth-store.ts +41 -0
- package/src/db/auth.ts +38 -0
- package/src/db/conversation.ts +39 -0
- package/src/db/event.ts +52 -0
- package/src/db/job-poll.ts +18 -0
- package/src/db/session.ts +60 -0
- package/src/db/supabase.ts +40 -383
- package/src/db/task.ts +69 -0
- package/src/db/types.ts +54 -0
- package/src/index.ts +2 -0
- package/src/mcp/agent-tools-server.ts +1047 -0
- package/src/mcp/browser-server.ts +258 -0
- package/src/tools/browser.ts +28 -1208
- package/src/tools/index.ts +32 -263
- 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
|
+
}
|
package/src/commands/job.ts
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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", {
|
package/src/commands/memory.ts
CHANGED
|
@@ -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
|
-
|
|
20
|
-
const mm = new MemoryManager(
|
|
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
|
-
|
|
70
|
-
const mm = new MemoryManager(
|
|
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
|
-
|
|
95
|
-
const mm = new MemoryManager(
|
|
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
|
-
|
|
120
|
-
const mm = new MemoryManager(
|
|
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
|
-
|
|
142
|
-
const mm = new MemoryManager(
|
|
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);
|
package/src/commands/schedule.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
67
|
-
const tasks = await listScheduledTasks(
|
|
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
|
-
|
|
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
|
-
|
|
110
|
-
const tasks = await listScheduledTasks(
|
|
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
|
-
|
|
130
|
-
const tasks = await listScheduledTasks(
|
|
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}`);
|
package/src/commands/start.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
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
|
}
|