autohand-cli 0.2.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.

Potentially problematic release.


This version of autohand-cli might be problematic. Click here for more details.

Files changed (48) hide show
  1. package/README.md +134 -0
  2. package/dist/agents-RB34F4XE.js +9 -0
  3. package/dist/agents-new-5I3B2W2I.js +9 -0
  4. package/dist/chunk-2EPIFDFM.js +68 -0
  5. package/dist/chunk-2NUX2RAI.js +145 -0
  6. package/dist/chunk-2QAL3HH4.js +79 -0
  7. package/dist/chunk-4UISIRMD.js +288 -0
  8. package/dist/chunk-55DQY6B5.js +49 -0
  9. package/dist/chunk-A7HRTONQ.js +382 -0
  10. package/dist/chunk-ALMJANSA.js +197 -0
  11. package/dist/chunk-GSOEIEOU.js +19 -0
  12. package/dist/chunk-I4HVBWYF.js +55 -0
  13. package/dist/chunk-KZ7VMQTC.js +20 -0
  14. package/dist/chunk-OC5YDNFC.js +373 -0
  15. package/dist/chunk-PQJIQBQ5.js +57 -0
  16. package/dist/chunk-PX5AGAEX.js +105 -0
  17. package/dist/chunk-QJ53OSGF.js +60 -0
  18. package/dist/chunk-SVLBJMYO.js +33 -0
  19. package/dist/chunk-TAZJSKFD.js +57 -0
  20. package/dist/chunk-TVWTD63Y.js +50 -0
  21. package/dist/chunk-UW2LYWIM.js +131 -0
  22. package/dist/chunk-VRI7EXV6.js +20 -0
  23. package/dist/chunk-XDVG3NM4.js +339 -0
  24. package/dist/chunk-YWKZF2SA.js +364 -0
  25. package/dist/chunk-ZWS3KSMK.js +30 -0
  26. package/dist/completion-Y42FKDT3.js +10 -0
  27. package/dist/export-WJ5P6E5Z.js +8 -0
  28. package/dist/feedback-NEDFOKMA.js +9 -0
  29. package/dist/formatters-UG6VZJJ5.js +8 -0
  30. package/dist/help-CNOV6OXY.js +10 -0
  31. package/dist/index.cjs +13418 -0
  32. package/dist/index.d.cts +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.js +10450 -0
  35. package/dist/init-DML7AOII.js +8 -0
  36. package/dist/lint-TA2ZHVLM.js +8 -0
  37. package/dist/login-GPXDNB2F.js +10 -0
  38. package/dist/logout-43W7N6JU.js +10 -0
  39. package/dist/memory-4GSP7NKV.js +8 -0
  40. package/dist/model-HKEFSH5E.js +8 -0
  41. package/dist/new-EEZC4XXV.js +8 -0
  42. package/dist/quit-RSYIERO5.js +8 -0
  43. package/dist/resume-2NERFSTD.js +8 -0
  44. package/dist/session-H5QWKE5E.js +8 -0
  45. package/dist/sessions-4KXIT76T.js +8 -0
  46. package/dist/status-XAJH67SE.js +8 -0
  47. package/dist/undo-7QJBXARS.js +8 -0
  48. package/package.json +69 -0
@@ -0,0 +1,373 @@
1
+ // src/commands/export.ts
2
+ import chalk from "chalk";
3
+ import path2 from "path";
4
+ import enquirer from "enquirer";
5
+
6
+ // src/session/exportSession.ts
7
+ import fs from "fs-extra";
8
+ import path from "path";
9
+ var DEFAULT_OPTIONS = {
10
+ includeToolOutputs: true,
11
+ includeTimestamps: false,
12
+ includeMetadata: true,
13
+ maxCodeBlockLength: 500,
14
+ includeToc: false
15
+ };
16
+ function formatCodeBlock(code, language, maxLength) {
17
+ let content = code;
18
+ if (maxLength && content.length > maxLength) {
19
+ content = content.slice(0, maxLength) + "\n... (truncated)";
20
+ }
21
+ const lang = language || "";
22
+ return "```" + lang + "\n" + content + "\n```";
23
+ }
24
+ function detectLanguage(content, context) {
25
+ if (context) {
26
+ const extMatch = context.match(/\.(\w+)$/);
27
+ if (extMatch) {
28
+ const ext = extMatch[1].toLowerCase();
29
+ const langMap = {
30
+ ts: "typescript",
31
+ tsx: "typescript",
32
+ js: "javascript",
33
+ jsx: "javascript",
34
+ py: "python",
35
+ rs: "rust",
36
+ go: "go",
37
+ rb: "ruby",
38
+ java: "java",
39
+ cpp: "cpp",
40
+ c: "c",
41
+ sh: "bash",
42
+ bash: "bash",
43
+ json: "json",
44
+ yaml: "yaml",
45
+ yml: "yaml",
46
+ md: "markdown",
47
+ sql: "sql",
48
+ html: "html",
49
+ css: "css"
50
+ };
51
+ return langMap[ext] || ext;
52
+ }
53
+ }
54
+ if (content.includes("function") || content.includes("const ") || content.includes("let ")) {
55
+ return "javascript";
56
+ }
57
+ if (content.includes("def ") || content.includes("import ") && content.includes(":")) {
58
+ return "python";
59
+ }
60
+ if (content.includes("fn ") || content.includes("let mut")) {
61
+ return "rust";
62
+ }
63
+ if (content.includes("func ") || content.includes("package ")) {
64
+ return "go";
65
+ }
66
+ return "";
67
+ }
68
+ function formatTimestamp(timestamp) {
69
+ const date = new Date(timestamp);
70
+ return date.toLocaleString("en-US", {
71
+ month: "short",
72
+ day: "numeric",
73
+ hour: "2-digit",
74
+ minute: "2-digit"
75
+ });
76
+ }
77
+ function formatMessage(message, options, index) {
78
+ const parts = [];
79
+ const roleEmoji = {
80
+ user: "\u{1F464}",
81
+ assistant: "\u{1F916}",
82
+ tool: "\u{1F527}",
83
+ system: "\u2699\uFE0F"
84
+ };
85
+ const emoji = roleEmoji[message.role] || "\u{1F4AC}";
86
+ const roleLabel = message.role.charAt(0).toUpperCase() + message.role.slice(1);
87
+ const timestamp = options.includeTimestamps && message.timestamp ? ` (${formatTimestamp(message.timestamp)})` : "";
88
+ parts.push(`### ${emoji} ${roleLabel}${timestamp}`);
89
+ parts.push("");
90
+ if (message.role === "tool") {
91
+ if (options.includeToolOutputs) {
92
+ const toolName = message.name || "Tool";
93
+ parts.push(`**${toolName}**`);
94
+ parts.push("");
95
+ if (message.content.includes("\n") || message.content.length > 100) {
96
+ const lang = detectLanguage(message.content, message.name);
97
+ parts.push(formatCodeBlock(message.content, lang, options.maxCodeBlockLength));
98
+ } else {
99
+ parts.push(`> ${message.content}`);
100
+ }
101
+ } else {
102
+ parts.push("*Tool output omitted*");
103
+ }
104
+ } else {
105
+ const content = message.content;
106
+ const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
107
+ let lastIndex = 0;
108
+ let match;
109
+ while ((match = codeBlockRegex.exec(content)) !== null) {
110
+ if (match.index > lastIndex) {
111
+ parts.push(content.slice(lastIndex, match.index).trim());
112
+ }
113
+ const lang = match[1] || "";
114
+ const code = match[2];
115
+ parts.push(formatCodeBlock(code, lang, options.maxCodeBlockLength));
116
+ lastIndex = match.index + match[0].length;
117
+ }
118
+ if (lastIndex < content.length) {
119
+ const remaining = content.slice(lastIndex).trim();
120
+ if (remaining) {
121
+ parts.push(remaining);
122
+ }
123
+ }
124
+ }
125
+ parts.push("");
126
+ parts.push("---");
127
+ parts.push("");
128
+ return parts.join("\n");
129
+ }
130
+ function exportToMarkdown(metadata2, messages, options = {}) {
131
+ const opts = { ...DEFAULT_OPTIONS, ...options };
132
+ const parts = [];
133
+ parts.push(`# ${metadata2.projectName} - Session ${metadata2.sessionId.slice(0, 8)}`);
134
+ parts.push("");
135
+ if (opts.includeMetadata) {
136
+ parts.push("## Session Info");
137
+ parts.push("");
138
+ parts.push(`| Property | Value |`);
139
+ parts.push(`|----------|-------|`);
140
+ parts.push(`| **Project** | ${metadata2.projectName} |`);
141
+ parts.push(`| **Started** | ${formatTimestamp(metadata2.createdAt)} |`);
142
+ if (metadata2.closedAt) {
143
+ parts.push(`| **Ended** | ${formatTimestamp(metadata2.closedAt)} |`);
144
+ }
145
+ parts.push(`| **Model** | ${metadata2.model} |`);
146
+ parts.push(`| **Messages** | ${metadata2.messageCount} |`);
147
+ parts.push(`| **Status** | ${metadata2.status} |`);
148
+ parts.push("");
149
+ if (metadata2.summary) {
150
+ parts.push("### Summary");
151
+ parts.push("");
152
+ parts.push(metadata2.summary);
153
+ parts.push("");
154
+ }
155
+ parts.push("---");
156
+ parts.push("");
157
+ }
158
+ if (opts.includeToc) {
159
+ parts.push("## Table of Contents");
160
+ parts.push("");
161
+ let userCount2 = 0;
162
+ for (const message of messages) {
163
+ if (message.role === "user") {
164
+ userCount2++;
165
+ const preview = message.content.slice(0, 50).replace(/\n/g, " ");
166
+ parts.push(`${userCount2}. [${preview}...](#message-${userCount2})`);
167
+ }
168
+ }
169
+ parts.push("");
170
+ parts.push("---");
171
+ parts.push("");
172
+ }
173
+ parts.push("## Conversation");
174
+ parts.push("");
175
+ let userCount = 0;
176
+ for (let i = 0; i < messages.length; i++) {
177
+ const message = messages[i];
178
+ if (opts.includeToc && message.role === "user") {
179
+ userCount++;
180
+ parts.push(`<a name="message-${userCount}"></a>`);
181
+ parts.push("");
182
+ }
183
+ parts.push(formatMessage(message, opts, i));
184
+ }
185
+ parts.push("---");
186
+ parts.push("");
187
+ parts.push(`*Exported from Autohand CLI on ${(/* @__PURE__ */ new Date()).toLocaleString()}*`);
188
+ return parts.join("\n");
189
+ }
190
+ function exportToJson(metadata2, messages, pretty = true) {
191
+ const data = {
192
+ metadata: metadata2,
193
+ messages,
194
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
195
+ version: "1.0"
196
+ };
197
+ return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
198
+ }
199
+ function exportToHtml(metadata2, messages, options = {}) {
200
+ const markdown = exportToMarkdown(metadata2, messages, options);
201
+ const html = markdown.replace(/^### (.*$)/gm, "<h3>$1</h3>").replace(/^## (.*$)/gm, "<h2>$1</h2>").replace(/^# (.*$)/gm, "<h1>$1</h1>").replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>").replace(/\*(.*?)\*/g, "<em>$1</em>").replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code class="language-$1">$2</code></pre>').replace(/`([^`]+)`/g, "<code>$1</code>").replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>').replace(/\|([^|]+)\|/g, "<td>$1</td>").replace(/^> (.*$)/gm, "<blockquote>$1</blockquote>").replace(/^---$/gm, "<hr>").replace(/\n\n/g, "</p><p>").replace(/\n/g, "<br>");
202
+ return `<!DOCTYPE html>
203
+ <html lang="en">
204
+ <head>
205
+ <meta charset="UTF-8">
206
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
207
+ <title>${metadata2.projectName} - Session ${metadata2.sessionId.slice(0, 8)}</title>
208
+ <style>
209
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 0 auto; padding: 2rem; line-height: 1.6; }
210
+ h1, h2, h3 { color: #333; }
211
+ pre { background: #f5f5f5; padding: 1rem; border-radius: 4px; overflow-x: auto; }
212
+ code { background: #f5f5f5; padding: 0.2rem 0.4rem; border-radius: 3px; font-size: 0.9em; }
213
+ pre code { background: none; padding: 0; }
214
+ blockquote { border-left: 4px solid #ddd; margin: 0; padding-left: 1rem; color: #666; }
215
+ hr { border: none; border-top: 1px solid #ddd; margin: 1.5rem 0; }
216
+ table { border-collapse: collapse; width: 100%; }
217
+ td, th { border: 1px solid #ddd; padding: 0.5rem; text-align: left; }
218
+ </style>
219
+ </head>
220
+ <body>
221
+ <p>${html}</p>
222
+ </body>
223
+ </html>`;
224
+ }
225
+ async function saveExport(content, filePath) {
226
+ await fs.ensureDir(path.dirname(filePath));
227
+ await fs.writeFile(filePath, content, "utf8");
228
+ }
229
+ function getSuggestedFilename(metadata2, format) {
230
+ const date = new Date(metadata2.createdAt);
231
+ const dateStr = date.toISOString().split("T")[0];
232
+ const projectSlug = metadata2.projectName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
233
+ const sessionShort = metadata2.sessionId.slice(0, 8);
234
+ return `${projectSlug}-${dateStr}-${sessionShort}.${format}`;
235
+ }
236
+
237
+ // src/commands/export.ts
238
+ var metadata = {
239
+ command: "/export",
240
+ description: "Export current session to markdown",
241
+ implemented: true
242
+ };
243
+ async function execute(args, context) {
244
+ if (!context?.sessionManager) {
245
+ console.log(chalk.red("Session manager not available."));
246
+ return;
247
+ }
248
+ const { sessionManager, currentSession, workspaceRoot } = context;
249
+ let session = currentSession;
250
+ if (!session) {
251
+ const sessions = await sessionManager.listSessions();
252
+ if (sessions.length === 0) {
253
+ console.log(chalk.yellow("No sessions found to export."));
254
+ return;
255
+ }
256
+ const { Select: Select2 } = enquirer;
257
+ const sessionPrompt = new Select2({
258
+ name: "session",
259
+ message: "Select a session to export:",
260
+ choices: sessions.slice(0, 10).map((s) => ({
261
+ name: s.sessionId,
262
+ message: `${s.projectName} - ${new Date(s.createdAt).toLocaleString()} (${s.messageCount} messages)`
263
+ }))
264
+ });
265
+ try {
266
+ const selectedId = await sessionPrompt.run();
267
+ session = await sessionManager.loadSession(selectedId);
268
+ } catch {
269
+ console.log(chalk.gray("Cancelled."));
270
+ return;
271
+ }
272
+ }
273
+ const metadata2 = session.metadata;
274
+ const messages = session.getMessages();
275
+ if (messages.length === 0) {
276
+ console.log(chalk.yellow("No messages in session to export."));
277
+ return;
278
+ }
279
+ const { Select, Confirm, Input } = enquirer;
280
+ const formatPrompt = new Select({
281
+ name: "format",
282
+ message: "Export format:",
283
+ choices: [
284
+ { name: "md", message: "Markdown (.md)" },
285
+ { name: "json", message: "JSON (.json)" },
286
+ { name: "html", message: "HTML (.html)" }
287
+ ]
288
+ });
289
+ let format;
290
+ try {
291
+ format = await formatPrompt.run();
292
+ } catch {
293
+ console.log(chalk.gray("Cancelled."));
294
+ return;
295
+ }
296
+ const options = {};
297
+ if (format === "md" || format === "html") {
298
+ const includeToolsPrompt = new Confirm({
299
+ name: "includeTools",
300
+ message: "Include tool outputs?",
301
+ initial: true
302
+ });
303
+ try {
304
+ options.includeToolOutputs = await includeToolsPrompt.run();
305
+ } catch {
306
+ options.includeToolOutputs = true;
307
+ }
308
+ const includeTocPrompt = new Confirm({
309
+ name: "includeToc",
310
+ message: "Include table of contents?",
311
+ initial: false
312
+ });
313
+ try {
314
+ options.includeToc = await includeTocPrompt.run();
315
+ } catch {
316
+ options.includeToc = false;
317
+ }
318
+ }
319
+ const suggestedFilename = getSuggestedFilename(metadata2, format);
320
+ const filenamePrompt = new Input({
321
+ name: "filename",
322
+ message: "Save as:",
323
+ initial: suggestedFilename
324
+ });
325
+ let filename;
326
+ try {
327
+ filename = await filenamePrompt.run();
328
+ } catch {
329
+ console.log(chalk.gray("Cancelled."));
330
+ return;
331
+ }
332
+ let content;
333
+ switch (format) {
334
+ case "md":
335
+ content = exportToMarkdown(metadata2, messages, options);
336
+ break;
337
+ case "json":
338
+ content = exportToJson(metadata2, messages);
339
+ break;
340
+ case "html":
341
+ content = exportToHtml(metadata2, messages, options);
342
+ break;
343
+ }
344
+ const filePath = path2.isAbsolute(filename) ? filename : path2.join(workspaceRoot, filename);
345
+ try {
346
+ await saveExport(content, filePath);
347
+ console.log();
348
+ console.log(chalk.green("Session exported successfully!"));
349
+ console.log(chalk.cyan(` ${filePath}`));
350
+ console.log(chalk.gray(` ${messages.length} messages, ${(Buffer.byteLength(content, "utf8") / 1024).toFixed(1)} KB`));
351
+ console.log();
352
+ } catch (error) {
353
+ console.log(chalk.red(`Failed to save export: ${error.message}`));
354
+ }
355
+ }
356
+
357
+ export {
358
+ metadata,
359
+ execute
360
+ };
361
+ /**
362
+ * @license
363
+ * Copyright 2025 Autohand AI LLC
364
+ * SPDX-License-Identifier: Apache-2.0
365
+ *
366
+ * Session Export
367
+ * Export sessions to markdown and other formats
368
+ */
369
+ /**
370
+ * @license
371
+ * Copyright 2025 Autohand AI LLC
372
+ * SPDX-License-Identifier: Apache-2.0
373
+ */
@@ -0,0 +1,57 @@
1
+ import {
2
+ getAuthClient,
3
+ saveConfig
4
+ } from "./chunk-A7HRTONQ.js";
5
+
6
+ // src/commands/logout.ts
7
+ import chalk from "chalk";
8
+ import enquirer from "enquirer";
9
+ var metadata = {
10
+ command: "/logout",
11
+ description: "sign out of your Autohand account",
12
+ implemented: true
13
+ };
14
+ async function logout(ctx) {
15
+ const config = ctx.config;
16
+ if (!config?.auth?.token) {
17
+ console.log(chalk.yellow("You are not currently logged in."));
18
+ console.log(chalk.gray("Use /login to sign in to your Autohand account."));
19
+ return null;
20
+ }
21
+ const userName = config.auth.user?.name || config.auth.user?.email || "user";
22
+ const { confirm } = await enquirer.prompt({
23
+ type: "confirm",
24
+ name: "confirm",
25
+ message: `Log out from ${chalk.cyan(userName)}?`,
26
+ initial: true
27
+ });
28
+ if (!confirm) {
29
+ console.log(chalk.gray("Logout cancelled."));
30
+ return null;
31
+ }
32
+ const authClient = getAuthClient();
33
+ try {
34
+ await authClient.logout(config.auth.token);
35
+ } catch {
36
+ }
37
+ const updatedConfig = {
38
+ ...config,
39
+ auth: void 0
40
+ };
41
+ await saveConfig(updatedConfig);
42
+ console.log();
43
+ console.log(chalk.green("Successfully logged out."));
44
+ console.log(chalk.gray("Your local session has been cleared."));
45
+ console.log();
46
+ return null;
47
+ }
48
+
49
+ export {
50
+ metadata,
51
+ logout
52
+ };
53
+ /**
54
+ * @license
55
+ * Copyright 2025 Autohand AI LLC
56
+ * SPDX-License-Identifier: Apache-2.0
57
+ */
@@ -0,0 +1,105 @@
1
+ import {
2
+ AUTOHAND_PATHS
3
+ } from "./chunk-2EPIFDFM.js";
4
+
5
+ // src/commands/agents-new.ts
6
+ import path from "path";
7
+ import fs from "fs-extra";
8
+ import chalk from "chalk";
9
+ import enquirer from "enquirer";
10
+ var metadata = {
11
+ command: "/agents new",
12
+ description: "create a new sub-agent from a description",
13
+ implemented: true,
14
+ prd: "prd/sub_agents_architecture.md"
15
+ };
16
+ async function createAgent(ctx) {
17
+ const answers = await enquirer.prompt([
18
+ {
19
+ type: "input",
20
+ name: "name",
21
+ message: "Agent name (e.g., Researcher, QA Tester)",
22
+ validate: (val) => typeof val === "string" && val.trim() ? true : "Name is required"
23
+ },
24
+ {
25
+ type: "input",
26
+ name: "description",
27
+ message: "Briefly describe what the agent should do"
28
+ }
29
+ ]);
30
+ const name = answers.name.trim();
31
+ const description = answers.description.trim();
32
+ if (!name) {
33
+ console.log(chalk.gray("Canceled: no name provided."));
34
+ return null;
35
+ }
36
+ const filename = await ensureUniqueFilename(name);
37
+ const filePath = path.join(getAgentsDir(), filename);
38
+ const prompt = buildPrompt(name, description);
39
+ let content;
40
+ try {
41
+ const completion = await ctx.llm.complete({
42
+ messages: [
43
+ {
44
+ role: "system",
45
+ content: "You generate concise markdown definitions for sub-agents. Output only markdown with no code fences. Keep it short but complete."
46
+ },
47
+ { role: "user", content: prompt }
48
+ ],
49
+ maxTokens: 600
50
+ });
51
+ content = completion.content.trim();
52
+ } catch (error) {
53
+ console.error(chalk.red(`Failed to generate agent: ${error.message}`));
54
+ return null;
55
+ }
56
+ try {
57
+ await fs.ensureDir(getAgentsDir());
58
+ await fs.writeFile(filePath, content + "\n", "utf8");
59
+ console.log(chalk.green(`Saved new agent to ${filePath}`));
60
+ } catch (error) {
61
+ console.error(chalk.red(`Failed to save agent: ${error.message}`));
62
+ return null;
63
+ }
64
+ return null;
65
+ }
66
+ function buildPrompt(name, description) {
67
+ return [
68
+ `Create a sub-agent markdown file for "${name}".`,
69
+ description ? `Agent description: ${description}` : "",
70
+ "Structure it as:",
71
+ "# <Name>",
72
+ "## Purpose",
73
+ "## Operating Mode (bullet list)",
74
+ "## Tools (bullet list; mention existing CLI tools and constraints briefly)",
75
+ "## Output Contract (what to return to main agent)",
76
+ "Be concise, 120-160 words total."
77
+ ].filter(Boolean).join("\n");
78
+ }
79
+ function getAgentsDir() {
80
+ return AUTOHAND_PATHS.agents;
81
+ }
82
+ function slugify(input) {
83
+ return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
84
+ }
85
+ async function ensureUniqueFilename(name) {
86
+ const base = slugify(name);
87
+ const dir = getAgentsDir();
88
+ let candidate = `${base}.md`;
89
+ let counter = 1;
90
+ while (await fs.pathExists(path.join(dir, candidate))) {
91
+ candidate = `${base}-${counter}.md`;
92
+ counter += 1;
93
+ }
94
+ return candidate;
95
+ }
96
+
97
+ export {
98
+ metadata,
99
+ createAgent
100
+ };
101
+ /**
102
+ * @license
103
+ * Copyright 2025 Autohand AI LLC
104
+ * SPDX-License-Identifier: Apache-2.0
105
+ */
@@ -0,0 +1,60 @@
1
+ // src/commands/sessions.ts
2
+ import chalk from "chalk";
3
+ var metadata = {
4
+ command: "/sessions",
5
+ description: "list all sessions",
6
+ implemented: true
7
+ };
8
+ async function sessions(ctx) {
9
+ const projectFilter = ctx.args.includes("--project") ? ctx.args[ctx.args.indexOf("--project") + 1] : void 0;
10
+ try {
11
+ const allSessions = await ctx.sessionManager.listSessions(
12
+ projectFilter ? { project: projectFilter } : void 0
13
+ );
14
+ if (allSessions.length === 0) {
15
+ console.log(chalk.gray("No sessions found."));
16
+ return null;
17
+ }
18
+ console.log(chalk.cyan(`
19
+ Sessions${projectFilter ? ` for ${projectFilter}` : ""}:
20
+ `));
21
+ console.log(
22
+ chalk.bold(
23
+ " ID".padEnd(25) + "Created".padEnd(20) + "Messages".padEnd(12) + "Summary"
24
+ )
25
+ );
26
+ console.log(chalk.gray("\u2500".repeat(80)));
27
+ for (const session of allSessions.slice(0, 20)) {
28
+ const id = session.sessionId.padEnd(24);
29
+ const created = new Date(session.createdAt).toLocaleString("en-US", {
30
+ month: "short",
31
+ day: "numeric",
32
+ hour: "numeric",
33
+ minute: "2-digit"
34
+ }).padEnd(19);
35
+ const messages = session.messageCount.toString().padEnd(11);
36
+ const summary = session.summary?.slice(0, 40) || chalk.gray("No summary");
37
+ console.log(` ${chalk.cyan(id)}${created}${messages}${summary}`);
38
+ }
39
+ if (allSessions.length > 20) {
40
+ console.log(chalk.gray(`
41
+ ... and ${allSessions.length - 20} more sessions`));
42
+ }
43
+ console.log(chalk.gray(`
44
+ Use ${chalk.white("/resume <id>")} to continue a session`));
45
+ return null;
46
+ } catch (error) {
47
+ console.error(chalk.red(`Failed to list sessions: ${error.message}`));
48
+ return null;
49
+ }
50
+ }
51
+
52
+ export {
53
+ metadata,
54
+ sessions
55
+ };
56
+ /**
57
+ * @license
58
+ * Copyright 2025 Autohand AI LLC
59
+ * SPDX-License-Identifier: Apache-2.0
60
+ */
@@ -0,0 +1,33 @@
1
+ // src/commands/session.ts
2
+ import chalk from "chalk";
3
+ var metadata = {
4
+ command: "/session",
5
+ description: "show the current session details",
6
+ implemented: true
7
+ };
8
+ async function session(ctx) {
9
+ const current = ctx.sessionManager.getCurrentSession();
10
+ if (!current) {
11
+ console.log(chalk.yellow("No active session."));
12
+ return null;
13
+ }
14
+ const meta = current.metadata;
15
+ console.log(chalk.cyan("\nCurrent session"));
16
+ console.log(`${chalk.gray(" ID:")} ${chalk.white(meta.sessionId)}`);
17
+ console.log(`${chalk.gray(" Project:")} ${chalk.white(meta.projectPath)}`);
18
+ console.log(`${chalk.gray(" Model:")} ${chalk.white(meta.model)}`);
19
+ console.log(`${chalk.gray(" Messages:")} ${chalk.white(meta.messageCount.toString())}`);
20
+ console.log(`${chalk.gray(" Started:")} ${chalk.white(new Date(meta.createdAt).toLocaleString())}`);
21
+ console.log();
22
+ return null;
23
+ }
24
+
25
+ export {
26
+ metadata,
27
+ session
28
+ };
29
+ /**
30
+ * @license
31
+ * Copyright 2025 Autohand AI LLC
32
+ * SPDX-License-Identifier: Apache-2.0
33
+ */
@@ -0,0 +1,57 @@
1
+ // src/commands/memory.ts
2
+ import chalk from "chalk";
3
+ async function memory(ctx) {
4
+ const { project, user } = await ctx.memoryManager.listAll();
5
+ console.log();
6
+ console.log(chalk.bold.cyan("Stored Memories"));
7
+ console.log(chalk.gray("\u2500".repeat(50)));
8
+ if (project.length === 0 && user.length === 0) {
9
+ console.log(chalk.gray("No memories stored yet."));
10
+ console.log();
11
+ console.log(chalk.gray("Tip: Type # followed by text to store a memory."));
12
+ console.log(chalk.gray("Example: # Always use TypeScript strict mode"));
13
+ return null;
14
+ }
15
+ if (project.length > 0) {
16
+ console.log();
17
+ console.log(chalk.bold.yellow("Project Memories") + chalk.gray(" (.autohand/memory/)"));
18
+ console.log();
19
+ for (const entry of project) {
20
+ const date = new Date(entry.updatedAt).toLocaleDateString();
21
+ const tags = entry.tags?.length ? chalk.cyan(` [${entry.tags.join(", ")}]`) : "";
22
+ console.log(chalk.white(` ${entry.content}`));
23
+ console.log(chalk.gray(` ID: ${entry.id} | Updated: ${date}${tags}`));
24
+ console.log();
25
+ }
26
+ }
27
+ if (user.length > 0) {
28
+ console.log();
29
+ console.log(chalk.bold.magenta("User Memories") + chalk.gray(" (~/.autohand/memory/)"));
30
+ console.log();
31
+ for (const entry of user) {
32
+ const date = new Date(entry.updatedAt).toLocaleDateString();
33
+ const tags = entry.tags?.length ? chalk.cyan(` [${entry.tags.join(", ")}]`) : "";
34
+ console.log(chalk.white(` ${entry.content}`));
35
+ console.log(chalk.gray(` ID: ${entry.id} | Updated: ${date}${tags}`));
36
+ console.log();
37
+ }
38
+ }
39
+ console.log(chalk.gray("\u2500".repeat(50)));
40
+ console.log(chalk.gray(`Total: ${project.length} project, ${user.length} user memories`));
41
+ return null;
42
+ }
43
+ var metadata = {
44
+ command: "/memory",
45
+ description: "view stored project and user memories",
46
+ implemented: true
47
+ };
48
+
49
+ export {
50
+ memory,
51
+ metadata
52
+ };
53
+ /**
54
+ * @license
55
+ * Copyright 2025 Autohand AI LLC
56
+ * SPDX-License-Identifier: Apache-2.0
57
+ */