assistme 0.2.8 → 0.2.9

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.
@@ -0,0 +1,47 @@
1
+ // src/utils/config.ts
2
+ import Conf from "conf";
3
+ import { resolve } from "path";
4
+ var SUPABASE_URL_DEFAULT = "https://msgplwbgohpokajtibew.supabase.co";
5
+ var SUPABASE_ANON_KEY_DEFAULT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im1zZ3Bsd2Jnb2hwb2thanRpYmV3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjE3MTMzNTEsImV4cCI6MjA3NzI4OTM1MX0.YqiluL_mIBWKv5dteIcPAPQ_jRp9rzZlvAXvkQttDjs";
6
+ var CONFIG_DEFAULTS = {
7
+ supabaseUrl: SUPABASE_URL_DEFAULT,
8
+ supabaseAnonKey: SUPABASE_ANON_KEY_DEFAULT,
9
+ sessionName: "Default",
10
+ model: "claude-sonnet-4-20250514",
11
+ maxTurns: 50
12
+ };
13
+ var config = new Conf({
14
+ projectName: "assistme",
15
+ defaults: CONFIG_DEFAULTS
16
+ });
17
+ function getConfig() {
18
+ const supabaseUrl = process.env.SUPABASE_URL || config.get("supabaseUrl") || SUPABASE_URL_DEFAULT;
19
+ const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || config.get("supabaseAnonKey") || SUPABASE_ANON_KEY_DEFAULT;
20
+ const anthropicApiKey = process.env.ANTHROPIC_API_KEY || config.get("anthropicApiKey") || "";
21
+ const workspacePath = config.get("workspacePath") || process.cwd();
22
+ return {
23
+ supabaseUrl,
24
+ supabaseAnonKey,
25
+ anthropicApiKey,
26
+ workspacePath: resolve(workspacePath),
27
+ sessionName: config.get("sessionName") || "Default",
28
+ model: config.get("model") || "claude-sonnet-4-20250514",
29
+ maxTurns: config.get("maxTurns") || 50
30
+ };
31
+ }
32
+ function setConfig(key, value) {
33
+ config.set(key, value);
34
+ }
35
+ function clearConfig() {
36
+ config.clear();
37
+ }
38
+ function getConfigPath() {
39
+ return config.path;
40
+ }
41
+
42
+ export {
43
+ getConfig,
44
+ setConfig,
45
+ clearConfig,
46
+ getConfigPath
47
+ };
@@ -0,0 +1,289 @@
1
+ import {
2
+ getConfig
3
+ } from "./chunk-TTEGHE2E.js";
4
+
5
+ // src/db/api-client.ts
6
+ import { existsSync, readFileSync } from "fs";
7
+ import { join } from "path";
8
+ import { homedir } from "os";
9
+ var AUTH_DIR = join(homedir(), ".config", "assistme");
10
+ var AUTH_FILE = join(AUTH_DIR, "auth.json");
11
+ function readAuthStore() {
12
+ try {
13
+ if (existsSync(AUTH_FILE)) {
14
+ return JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
15
+ }
16
+ } catch {
17
+ }
18
+ return {};
19
+ }
20
+ function getRawToken() {
21
+ const store = readAuthStore();
22
+ const token = store["mcp_token"];
23
+ if (!token || !token.startsWith("am_")) {
24
+ throw new Error("Not authenticated. Run `assistme login`.");
25
+ }
26
+ return token;
27
+ }
28
+ async function callMcpHandler(action, params = {}, overrideToken) {
29
+ const config = getConfig();
30
+ const token = overrideToken || getRawToken();
31
+ const url = `${config.supabaseUrl}/functions/v1/mcp-handler`;
32
+ const response = await fetch(url, {
33
+ method: "POST",
34
+ headers: {
35
+ "Content-Type": "application/json",
36
+ Authorization: `Bearer ${token}`,
37
+ apikey: config.supabaseAnonKey
38
+ },
39
+ body: JSON.stringify({ action, params })
40
+ });
41
+ const body = await response.json();
42
+ if (!response.ok || body.error) {
43
+ throw new Error(body.error || `Request failed: ${response.status}`);
44
+ }
45
+ return body.data;
46
+ }
47
+
48
+ // src/utils/logger.ts
49
+ import chalk from "chalk";
50
+ import { randomUUID } from "crypto";
51
+ var currentLevel = "info";
52
+ var currentCorrelationId = null;
53
+ var LEVEL_ORDER = {
54
+ debug: 0,
55
+ info: 1,
56
+ warn: 2,
57
+ error: 3
58
+ };
59
+ function setLogLevel(level) {
60
+ currentLevel = level;
61
+ }
62
+ function setCorrelationId(id) {
63
+ currentCorrelationId = id;
64
+ }
65
+ function newCorrelationId() {
66
+ const id = randomUUID().slice(0, 8);
67
+ currentCorrelationId = id;
68
+ return id;
69
+ }
70
+ function shouldLog(level) {
71
+ return LEVEL_ORDER[level] >= LEVEL_ORDER[currentLevel];
72
+ }
73
+ function timestamp() {
74
+ return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
75
+ }
76
+ function prefix() {
77
+ const ts = timestamp();
78
+ return currentCorrelationId ? `${ts} ${currentCorrelationId}` : ts;
79
+ }
80
+ var log = {
81
+ debug(msg, ...args) {
82
+ if (shouldLog("debug")) {
83
+ console.log(chalk.gray(`[${prefix()}] DEBUG`), msg, ...args);
84
+ }
85
+ },
86
+ info(msg, ...args) {
87
+ if (shouldLog("info")) {
88
+ console.log(chalk.blue(`[${prefix()}]`), msg, ...args);
89
+ }
90
+ },
91
+ success(msg, ...args) {
92
+ if (shouldLog("info")) {
93
+ console.log(chalk.green(`[${prefix()}] \u2713`), msg, ...args);
94
+ }
95
+ },
96
+ warn(msg, ...args) {
97
+ if (shouldLog("warn")) {
98
+ console.log(chalk.yellow(`[${prefix()}] WARN`), msg, ...args);
99
+ }
100
+ },
101
+ error(msg, ...args) {
102
+ if (shouldLog("error")) {
103
+ console.error(chalk.red(`[${prefix()}] ERROR`), msg, ...args);
104
+ }
105
+ },
106
+ agent(msg) {
107
+ console.log(chalk.cyan(" \u25B8"), msg);
108
+ },
109
+ tool(name, msg) {
110
+ console.log(chalk.magenta(` \u26A1 ${name}:`), msg);
111
+ },
112
+ result(msg) {
113
+ console.log(chalk.green(" \u2190"), msg);
114
+ }
115
+ };
116
+
117
+ // src/agent/job-runner.ts
118
+ var JobRunner = class {
119
+ constructor(_userId) {
120
+ }
121
+ /**
122
+ * Load a job and its linked skills from the database.
123
+ * Skills are the agent's *capabilities* — not a fixed execution plan.
124
+ */
125
+ async loadJob(jobName) {
126
+ try {
127
+ const data = await callMcpHandler(
128
+ "job.get_with_skills",
129
+ { job_name: jobName }
130
+ );
131
+ if (!data || data.length === 0) {
132
+ return null;
133
+ }
134
+ const rows = data;
135
+ const first = rows[0];
136
+ return {
137
+ jobId: first.job_id,
138
+ jobName: first.job_name,
139
+ jobDescription: first.job_description,
140
+ skills: rows.map((row) => ({
141
+ skillId: row.skill_id,
142
+ skillName: row.skill_name,
143
+ skillDescription: row.skill_description || "",
144
+ skillEmoji: row.skill_emoji || "",
145
+ skillContent: row.skill_content || ""
146
+ }))
147
+ };
148
+ } catch (err) {
149
+ log.debug(`Failed to load job "${jobName}": ${err}`);
150
+ return null;
151
+ }
152
+ }
153
+ /**
154
+ * List all jobs for the user.
155
+ */
156
+ async listJobs() {
157
+ try {
158
+ const data = await callMcpHandler(
159
+ "job.list"
160
+ );
161
+ return (data || []).map((row) => ({
162
+ id: row.id,
163
+ name: row.name,
164
+ description: row.description,
165
+ skillCount: row.skill_count || 0
166
+ }));
167
+ } catch (err) {
168
+ log.debug(`Failed to list jobs: ${err}`);
169
+ return [];
170
+ }
171
+ }
172
+ /**
173
+ * Create a job run record.
174
+ * This is just a timestamp + status tracker. The actual execution trace
175
+ * lives in the conversation transcript (message_events).
176
+ */
177
+ async createRun(jobId, options) {
178
+ try {
179
+ const data = await callMcpHandler("job.create_run", {
180
+ job_id: jobId,
181
+ session_id: options?.sessionId || null,
182
+ message_id: options?.messageId || null,
183
+ trigger_type: options?.triggerType || "manual"
184
+ });
185
+ return data;
186
+ } catch (err) {
187
+ log.debug(`Job run creation error: ${err}`);
188
+ return null;
189
+ }
190
+ }
191
+ /**
192
+ * Mark a job run as completed/failed.
193
+ * Throws on failure so callers can handle (e.g. avoid duplicate execution).
194
+ */
195
+ async completeRun(runId, status = "completed", summary) {
196
+ await callMcpHandler("job.complete_run", {
197
+ run_id: runId,
198
+ status,
199
+ summary: summary?.slice(0, 1e4) || null
200
+ });
201
+ }
202
+ /**
203
+ * Get recent job run history.
204
+ */
205
+ async getRunHistory(jobName, limit = 10) {
206
+ try {
207
+ const data = await callMcpHandler(
208
+ "job.get_runs",
209
+ { job_name: jobName || null, limit }
210
+ );
211
+ return (data || []).map((row) => ({
212
+ runId: row.run_id,
213
+ jobName: row.job_name,
214
+ status: row.status,
215
+ triggerType: row.trigger_type,
216
+ startedAt: row.started_at,
217
+ completedAt: row.completed_at || null,
218
+ summary: row.summary || null
219
+ }));
220
+ } catch (err) {
221
+ log.debug(`Run history error: ${err}`);
222
+ return [];
223
+ }
224
+ }
225
+ /**
226
+ * Build the agentic prompt for the agent to execute a job.
227
+ *
228
+ * This does NOT prescribe a fixed sequence. Instead, it tells the agent
229
+ * the job's goal and lists available skills as capabilities. The agent
230
+ * decides dynamically which skills to use, in what order, and how to
231
+ * chain them based on what it discovers at runtime.
232
+ */
233
+ buildJobPrompt(job, runId) {
234
+ let prompt = `## Job: ${job.jobName}
235
+ `;
236
+ prompt += `*${job.jobDescription}*
237
+
238
+ `;
239
+ prompt += `**Run ID:** ${runId}
240
+
241
+ `;
242
+ prompt += `You are now acting as "${job.jobName}". `;
243
+ prompt += `Your goal is to accomplish the objectives described above using the skills and tools available to you.
244
+
245
+ `;
246
+ prompt += `### Available Skills
247
+ `;
248
+ prompt += `These skills are your capabilities for this job. `;
249
+ prompt += `Use \`skill_invoke\` to load any skill's full instructions when you need it. `;
250
+ prompt += `You do NOT need to use all of them \u2014 pick the ones relevant to the current situation.
251
+
252
+ `;
253
+ for (const skill of job.skills) {
254
+ const emoji = skill.skillEmoji ? `${skill.skillEmoji} ` : "";
255
+ prompt += `- **${emoji}${skill.skillName}**: ${skill.skillDescription}
256
+ `;
257
+ }
258
+ prompt += `
259
+ ### How to Work
260
+ `;
261
+ prompt += `- **Be agentic**: Decide what to do based on what you discover. `;
262
+ prompt += `If checking Slack reveals a request that requires GitHub work, go do the GitHub work immediately \u2014 don't just note it for later.
263
+ `;
264
+ prompt += `- **Chain dynamically**: One skill's output should inform your next action. `;
265
+ prompt += `For example, if you find an assigned GitHub issue, use your coding skills to implement it.
266
+ `;
267
+ prompt += `- **Skip what's irrelevant**: If a capability doesn't apply right now, skip it.
268
+ `;
269
+ prompt += `- **Use tools directly too**: You also have browser, file, and shell tools. `;
270
+ prompt += `Use them directly when a skill isn't needed \u2014 skills are guides, not mandatory steps.
271
+ `;
272
+ prompt += `- **Respond and act**: If you find messages or issues that need replies, reply to them. `;
273
+ prompt += `If you find code tasks, implement them.
274
+
275
+ `;
276
+ prompt += `When finished, provide a summary of what you accomplished and any items that need the user's attention.
277
+ `;
278
+ return prompt;
279
+ }
280
+ };
281
+
282
+ export {
283
+ callMcpHandler,
284
+ setLogLevel,
285
+ setCorrelationId,
286
+ newCorrelationId,
287
+ log,
288
+ JobRunner
289
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ clearConfig,
3
+ getConfig,
4
+ getConfigPath,
5
+ setConfig
6
+ } from "./chunk-TTEGHE2E.js";
7
+ export {
8
+ clearConfig,
9
+ getConfig,
10
+ getConfigPath,
11
+ setConfig
12
+ };