@stackmemoryai/stackmemory 0.5.51 → 0.5.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/handoff.js +215 -59
- package/dist/cli/commands/handoff.js.map +2 -2
- package/dist/cli/index.js +8 -2
- package/dist/cli/index.js.map +2 -2
- package/dist/integrations/claude-code/lifecycle-hooks.js +3 -3
- package/dist/integrations/claude-code/lifecycle-hooks.js.map +1 -1
- package/package.json +1 -1
- package/scripts/auto-handoff.sh +1 -1
- package/scripts/claude-sm-autostart.js +174 -132
- package/scripts/setup-claude-integration.js +14 -10
- package/scripts/stackmemory-auto-handoff.sh +3 -3
- package/scripts/test-session-handoff.sh +2 -2
- package/dist/core/context/compaction-handler.js +0 -330
- package/dist/core/context/compaction-handler.js.map +0 -7
- package/dist/core/context/context-bridge.js +0 -238
- package/dist/core/context/context-bridge.js.map +0 -7
- package/scripts/testing/scripts/testing/ab-test-runner.js +0 -363
- package/scripts/testing/scripts/testing/collect-metrics.js +0 -292
- package/scripts/testing/src/core/context/context-bridge.js +0 -253
- package/scripts/testing/src/core/context/frame-manager.js +0 -746
- package/scripts/testing/src/core/context/shared-context-layer.js +0 -437
- package/scripts/testing/src/core/database/database-adapter.js +0 -54
- package/scripts/testing/src/core/errors/index.js +0 -291
- package/scripts/testing/src/core/errors/recovery.js +0 -268
- package/scripts/testing/src/core/monitoring/logger.js +0 -145
- package/scripts/testing/src/core/retrieval/context-retriever.js +0 -516
- package/scripts/testing/src/core/session/index.js +0 -1
- package/scripts/testing/src/core/session/session-manager.js +0 -323
- package/scripts/testing/src/core/trace/cli-trace-wrapper.js +0 -140
- package/scripts/testing/src/core/trace/db-trace-wrapper.js +0 -251
- package/scripts/testing/src/core/trace/debug-trace.js +0 -398
- package/scripts/testing/src/core/trace/index.js +0 -120
- package/scripts/testing/src/core/trace/linear-api-wrapper.js +0 -204
|
@@ -3,7 +3,7 @@ import { dirname as __pathDirname } from 'path';
|
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
-
import { execSync, execFileSync } from "child_process";
|
|
6
|
+
import { execSync, execFileSync, spawn } from "child_process";
|
|
7
7
|
import {
|
|
8
8
|
existsSync,
|
|
9
9
|
readFileSync,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
unlinkSync
|
|
14
14
|
} from "fs";
|
|
15
15
|
import { join } from "path";
|
|
16
|
+
import { homedir } from "os";
|
|
16
17
|
import Database from "better-sqlite3";
|
|
17
18
|
import { z } from "zod";
|
|
18
19
|
import { FrameManager } from "../../core/context/index.js";
|
|
@@ -53,10 +54,9 @@ const CommitMessageSchema = z.string().min(1, "Commit message cannot be empty").
|
|
|
53
54
|
(msg) => !msg.includes("`"),
|
|
54
55
|
"Commit message cannot contain backticks"
|
|
55
56
|
);
|
|
56
|
-
function
|
|
57
|
-
const cmd = new Command("
|
|
58
|
-
cmd.description("
|
|
59
|
-
cmd.command("capture", { isDefault: true }).description("Commit current work and generate a handoff prompt").option("-m, --message <message>", "Custom commit message").option("--no-commit", "Skip git commit").option("--copy", "Copy the handoff prompt to clipboard").option("--basic", "Use basic handoff format instead of enhanced").action(async (options) => {
|
|
57
|
+
function createCaptureCommand() {
|
|
58
|
+
const cmd = new Command("capture");
|
|
59
|
+
cmd.description("Commit current work and generate a handoff prompt").option("-m, --message <message>", "Custom commit message").option("--no-commit", "Skip git commit").option("--copy", "Copy the handoff prompt to clipboard").option("--basic", "Use basic handoff format instead of enhanced").action(async (options) => {
|
|
60
60
|
try {
|
|
61
61
|
const projectRoot = process.cwd();
|
|
62
62
|
const dbPath = join(projectRoot, ".stackmemory", "context.db");
|
|
@@ -229,7 +229,7 @@ ${notes}
|
|
|
229
229
|
- \`stackmemory log recent\` - View recent activity
|
|
230
230
|
|
|
231
231
|
---
|
|
232
|
-
Generated by stackmemory
|
|
232
|
+
Generated by stackmemory capture at ${timestamp}
|
|
233
233
|
`;
|
|
234
234
|
} else {
|
|
235
235
|
const enhancedGenerator = new EnhancedHandoffGenerator(projectRoot);
|
|
@@ -289,12 +289,16 @@ Generated by stackmemory handoff at ${timestamp}
|
|
|
289
289
|
\u{1F4BE} Handoff saved to: ${handoffPath}`);
|
|
290
290
|
console.log("\u{1F4CB} Use this prompt when starting your next session");
|
|
291
291
|
} catch (error) {
|
|
292
|
-
logger.error("
|
|
293
|
-
console.error("\u274C
|
|
292
|
+
logger.error("Capture command failed", error);
|
|
293
|
+
console.error("\u274C Capture failed:", error.message);
|
|
294
294
|
process.exit(1);
|
|
295
295
|
}
|
|
296
296
|
});
|
|
297
|
-
cmd
|
|
297
|
+
return cmd;
|
|
298
|
+
}
|
|
299
|
+
function createRestoreCommand() {
|
|
300
|
+
const cmd = new Command("restore");
|
|
301
|
+
cmd.description("Restore context from last handoff").option("--no-copy", "Do not copy prompt to clipboard").action(async (options) => {
|
|
298
302
|
try {
|
|
299
303
|
const projectRoot = process.cwd();
|
|
300
304
|
const handoffPath = join(
|
|
@@ -310,7 +314,7 @@ Generated by stackmemory handoff at ${timestamp}
|
|
|
310
314
|
);
|
|
311
315
|
if (!existsSync(handoffPath)) {
|
|
312
316
|
console.log("\u274C No handoff found in this project");
|
|
313
|
-
console.log('\u{1F4A1} Run "stackmemory
|
|
317
|
+
console.log('\u{1F4A1} Run "stackmemory capture" to create one');
|
|
314
318
|
return;
|
|
315
319
|
}
|
|
316
320
|
const handoffPrompt = readFileSync(handoffPath, "utf-8");
|
|
@@ -362,72 +366,224 @@ Generated by stackmemory handoff at ${timestamp}
|
|
|
362
366
|
}
|
|
363
367
|
console.log("\n\u{1F680} Ready to continue where you left off!");
|
|
364
368
|
} catch (error) {
|
|
365
|
-
logger.error("
|
|
369
|
+
logger.error("Restore failed", error);
|
|
366
370
|
console.error("\u274C Restore failed:", error.message);
|
|
367
371
|
process.exit(1);
|
|
368
372
|
}
|
|
369
373
|
});
|
|
370
|
-
cmd
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
374
|
+
return cmd;
|
|
375
|
+
}
|
|
376
|
+
async function captureHandoff(reason, exitCode, wrappedCommand, sessionStart, quiet) {
|
|
377
|
+
const projectRoot = process.cwd();
|
|
378
|
+
const handoffDir = join(homedir(), ".stackmemory", "handoffs");
|
|
379
|
+
const logFile = join(handoffDir, "auto-handoff.log");
|
|
380
|
+
if (!existsSync(handoffDir)) {
|
|
381
|
+
mkdirSync(handoffDir, { recursive: true });
|
|
382
|
+
}
|
|
383
|
+
const logMessage = (msg) => {
|
|
384
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
|
|
385
|
+
const logLine = `[${timestamp}] ${msg}
|
|
386
|
+
`;
|
|
387
|
+
try {
|
|
388
|
+
writeFileSync(logFile, logLine, { flag: "a" });
|
|
389
|
+
} catch {
|
|
383
390
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
+
};
|
|
392
|
+
if (!quiet) {
|
|
393
|
+
console.log("\nCapturing handoff context...");
|
|
394
|
+
}
|
|
395
|
+
logMessage(`Capturing handoff: reason=${reason}, exit_code=${exitCode}`);
|
|
396
|
+
try {
|
|
397
|
+
execFileSync(
|
|
398
|
+
process.execPath,
|
|
399
|
+
[process.argv[1], "capture", "--no-commit"],
|
|
400
|
+
{
|
|
401
|
+
cwd: projectRoot,
|
|
402
|
+
stdio: quiet ? "pipe" : "inherit"
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
const metadata = {
|
|
406
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
407
|
+
reason,
|
|
408
|
+
exit_code: exitCode,
|
|
409
|
+
command: wrappedCommand,
|
|
410
|
+
pid: process.pid,
|
|
411
|
+
cwd: projectRoot,
|
|
412
|
+
user: process.env["USER"] || "unknown",
|
|
413
|
+
session_duration: Math.floor((Date.now() - sessionStart) / 1e3)
|
|
414
|
+
};
|
|
415
|
+
const metadataPath = join(handoffDir, "last-handoff-meta.json");
|
|
416
|
+
writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
417
|
+
if (!quiet) {
|
|
418
|
+
console.log("Handoff captured successfully");
|
|
419
|
+
logMessage(`Handoff captured: ${metadataPath}`);
|
|
420
|
+
console.log("\nSession Summary:");
|
|
421
|
+
console.log(` Duration: ${metadata.session_duration} seconds`);
|
|
422
|
+
console.log(` Exit reason: ${reason}`);
|
|
391
423
|
try {
|
|
392
|
-
const
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
if (validationError instanceof z.ZodError) {
|
|
400
|
-
console.error("\u274C Invalid command:");
|
|
401
|
-
validationError.errors.forEach((err) => {
|
|
402
|
-
console.error(` ${err.message}`);
|
|
403
|
-
});
|
|
404
|
-
} else {
|
|
405
|
-
console.error(
|
|
406
|
-
"\u274C Failed to execute command:",
|
|
407
|
-
validationError.message
|
|
408
|
-
);
|
|
424
|
+
const gitStatus = execSync("git status --short", {
|
|
425
|
+
encoding: "utf-8",
|
|
426
|
+
cwd: projectRoot
|
|
427
|
+
}).trim();
|
|
428
|
+
if (gitStatus) {
|
|
429
|
+
console.log("\nYou have uncommitted changes");
|
|
430
|
+
console.log(' Run "git status" to review');
|
|
409
431
|
}
|
|
410
|
-
|
|
432
|
+
} catch {
|
|
411
433
|
}
|
|
412
|
-
|
|
413
|
-
|
|
434
|
+
console.log('\nRun "stackmemory restore" in your next session');
|
|
435
|
+
}
|
|
436
|
+
} catch (err) {
|
|
437
|
+
if (!quiet) {
|
|
438
|
+
console.error("Failed to capture handoff:", err.message);
|
|
439
|
+
}
|
|
440
|
+
logMessage(`ERROR: ${err.message}`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function createAutoCaptureCommand() {
|
|
444
|
+
const cmd = new Command("auto-capture");
|
|
445
|
+
cmd.description("Wrap a command with automatic handoff capture on termination").option("-a, --auto", "Auto-capture on normal exit (no prompt)").option("-q, --quiet", "Suppress output").option("-t, --tag <tag>", "Tag this session").argument("[command...]", "Command to wrap with auto-handoff").action(async (commandArgs, options) => {
|
|
446
|
+
const autoCapture = options.auto || false;
|
|
447
|
+
const quiet = options.quiet || false;
|
|
448
|
+
const tag = options.tag || "";
|
|
449
|
+
if (!commandArgs || commandArgs.length === 0) {
|
|
450
|
+
console.log("StackMemory Auto-Handoff");
|
|
451
|
+
console.log("-".repeat(50));
|
|
452
|
+
console.log("");
|
|
453
|
+
console.log(
|
|
454
|
+
"Wraps a command with automatic handoff capture on termination."
|
|
455
|
+
);
|
|
414
456
|
console.log("");
|
|
415
|
-
console.log("
|
|
416
|
-
console.log(
|
|
457
|
+
console.log("Usage:");
|
|
458
|
+
console.log(" stackmemory auto-capture [options] <command> [args...]");
|
|
417
459
|
console.log("");
|
|
418
|
-
console.log("
|
|
419
|
-
console.log(
|
|
420
|
-
console.log(
|
|
460
|
+
console.log("Examples:");
|
|
461
|
+
console.log(" stackmemory auto-capture claude");
|
|
462
|
+
console.log(" stackmemory auto-capture -a npm run dev");
|
|
463
|
+
console.log(' stackmemory auto-capture -t "feature-work" vim');
|
|
421
464
|
console.log("");
|
|
422
|
-
console.log("
|
|
465
|
+
console.log("Options:");
|
|
423
466
|
console.log(
|
|
424
|
-
|
|
467
|
+
" -a, --auto Auto-capture on normal exit (no prompt)"
|
|
425
468
|
);
|
|
469
|
+
console.log(" -q, --quiet Suppress output");
|
|
470
|
+
console.log(" -t, --tag <tag> Tag this session");
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
const wrappedCommand = commandArgs.join(" ");
|
|
474
|
+
const sessionStart = Date.now();
|
|
475
|
+
let capturedAlready = false;
|
|
476
|
+
if (!quiet) {
|
|
477
|
+
console.log("StackMemory Auto-Handoff Wrapper");
|
|
478
|
+
console.log(`Wrapping: ${wrappedCommand}`);
|
|
479
|
+
if (tag) {
|
|
480
|
+
console.log(`Tag: ${tag}`);
|
|
481
|
+
}
|
|
482
|
+
console.log("Handoff will be captured on termination");
|
|
483
|
+
console.log("");
|
|
426
484
|
}
|
|
485
|
+
const [cmd2, ...args] = commandArgs;
|
|
486
|
+
let childProcess;
|
|
487
|
+
try {
|
|
488
|
+
childProcess = spawn(cmd2, args, {
|
|
489
|
+
stdio: "inherit",
|
|
490
|
+
shell: false,
|
|
491
|
+
cwd: process.cwd(),
|
|
492
|
+
env: process.env
|
|
493
|
+
});
|
|
494
|
+
} catch (err) {
|
|
495
|
+
console.error(`Failed to start command: ${err.message}`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const handleSignal = async (signal, exitCode) => {
|
|
500
|
+
if (capturedAlready) return;
|
|
501
|
+
capturedAlready = true;
|
|
502
|
+
if (!quiet) {
|
|
503
|
+
console.log(`
|
|
504
|
+
Received ${signal}`);
|
|
505
|
+
}
|
|
506
|
+
if (childProcess.pid && !childProcess.killed) {
|
|
507
|
+
childProcess.kill(signal);
|
|
508
|
+
}
|
|
509
|
+
await captureHandoff(
|
|
510
|
+
signal,
|
|
511
|
+
exitCode,
|
|
512
|
+
wrappedCommand,
|
|
513
|
+
sessionStart,
|
|
514
|
+
quiet
|
|
515
|
+
);
|
|
516
|
+
process.exit(exitCode);
|
|
517
|
+
};
|
|
518
|
+
process.on("SIGINT", () => handleSignal("SIGINT", 130));
|
|
519
|
+
process.on("SIGTERM", () => handleSignal("SIGTERM", 143));
|
|
520
|
+
process.on("SIGHUP", () => handleSignal("SIGHUP", 129));
|
|
521
|
+
childProcess.on("exit", async (code, signal) => {
|
|
522
|
+
if (capturedAlready) return;
|
|
523
|
+
capturedAlready = true;
|
|
524
|
+
const exitCode = code ?? (signal ? 128 : 0);
|
|
525
|
+
if (signal) {
|
|
526
|
+
await captureHandoff(
|
|
527
|
+
signal,
|
|
528
|
+
exitCode,
|
|
529
|
+
wrappedCommand,
|
|
530
|
+
sessionStart,
|
|
531
|
+
quiet
|
|
532
|
+
);
|
|
533
|
+
} else if (exitCode !== 0) {
|
|
534
|
+
if (!quiet) {
|
|
535
|
+
console.log(`
|
|
536
|
+
Command exited with code: ${exitCode}`);
|
|
537
|
+
}
|
|
538
|
+
await captureHandoff(
|
|
539
|
+
"unexpected_exit",
|
|
540
|
+
exitCode,
|
|
541
|
+
wrappedCommand,
|
|
542
|
+
sessionStart,
|
|
543
|
+
quiet
|
|
544
|
+
);
|
|
545
|
+
} else if (autoCapture) {
|
|
546
|
+
await captureHandoff(
|
|
547
|
+
"normal_exit",
|
|
548
|
+
0,
|
|
549
|
+
wrappedCommand,
|
|
550
|
+
sessionStart,
|
|
551
|
+
quiet
|
|
552
|
+
);
|
|
553
|
+
} else {
|
|
554
|
+
if (process.stdin.isTTY) {
|
|
555
|
+
console.log(
|
|
556
|
+
"\nSession ending. Use -a flag for auto-capture on normal exit."
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
process.exit(exitCode);
|
|
561
|
+
});
|
|
562
|
+
childProcess.on("error", async (err) => {
|
|
563
|
+
if (capturedAlready) return;
|
|
564
|
+
capturedAlready = true;
|
|
565
|
+
console.error(`Command error: ${err.message}`);
|
|
566
|
+
await captureHandoff(
|
|
567
|
+
"spawn_error",
|
|
568
|
+
1,
|
|
569
|
+
wrappedCommand,
|
|
570
|
+
sessionStart,
|
|
571
|
+
quiet
|
|
572
|
+
);
|
|
573
|
+
process.exit(1);
|
|
574
|
+
});
|
|
427
575
|
});
|
|
428
576
|
return cmd;
|
|
429
577
|
}
|
|
578
|
+
function createHandoffCommand() {
|
|
579
|
+
const cmd = new Command("handoff");
|
|
580
|
+
cmd.description('(deprecated) Use "capture" or "restore" instead');
|
|
581
|
+
return cmd;
|
|
582
|
+
}
|
|
430
583
|
export {
|
|
431
|
-
|
|
584
|
+
createAutoCaptureCommand,
|
|
585
|
+
createCaptureCommand,
|
|
586
|
+
createHandoffCommand,
|
|
587
|
+
createRestoreCommand
|
|
432
588
|
};
|
|
433
589
|
//# sourceMappingURL=handoff.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/cli/commands/handoff.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Handoff command - Commits work and generates a prompt for the next session\n */\n\nimport { Command } from 'commander';\nimport { execSync, execFileSync } from 'child_process';\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n mkdirSync,\n readdirSync,\n unlinkSync,\n} from 'fs';\nimport { join } from 'path';\nimport Database from 'better-sqlite3';\nimport { z } from 'zod';\nimport { FrameManager } from '../../core/context/index.js';\nimport { LinearTaskManager } from '../../features/tasks/linear-task-manager.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { EnhancedHandoffGenerator } from '../../core/session/enhanced-handoff.js';\n\n// Handoff versioning - keep last N handoffs\nconst MAX_HANDOFF_VERSIONS = 10;\n\nfunction saveVersionedHandoff(\n projectRoot: string,\n branch: string,\n content: string\n): string {\n const handoffsDir = join(projectRoot, '.stackmemory', 'handoffs');\n if (!existsSync(handoffsDir)) {\n mkdirSync(handoffsDir, { recursive: true });\n }\n\n // Generate versioned filename: YYYY-MM-DD-HH-mm-branch.md\n const now = new Date();\n const timestamp = now.toISOString().slice(0, 16).replace(/[T:]/g, '-');\n const safeBranch = branch.replace(/[^a-zA-Z0-9-]/g, '-').slice(0, 30);\n const filename = `${timestamp}-${safeBranch}.md`;\n const versionedPath = join(handoffsDir, filename);\n\n // Save versioned handoff\n writeFileSync(versionedPath, content);\n\n // Clean up old handoffs (keep last N)\n try {\n const files = readdirSync(handoffsDir)\n .filter((f) => f.endsWith('.md'))\n .sort()\n .reverse();\n\n for (const oldFile of files.slice(MAX_HANDOFF_VERSIONS)) {\n unlinkSync(join(handoffsDir, oldFile));\n }\n } catch {\n // Cleanup failed, not critical\n }\n\n return versionedPath;\n}\n\n// Input validation schemas\nconst CommitMessageSchema = z\n .string()\n .min(1, 'Commit message cannot be empty')\n .max(200, 'Commit message too long')\n .regex(\n /^[a-zA-Z0-9\\s\\-_.,:()\\/\\[\\]]+$/,\n 'Commit message contains invalid characters'\n )\n .refine(\n (msg) => !msg.includes('\\n'),\n 'Commit message cannot contain newlines'\n )\n .refine(\n (msg) => !msg.includes('\"'),\n 'Commit message cannot contain double quotes'\n )\n .refine(\n (msg) => !msg.includes('`'),\n 'Commit message cannot contain backticks'\n );\n\nexport function createHandoffCommand(): Command {\n const cmd = new Command('handoff');\n\n cmd.description('Session handoff for continuity between Claude sessions');\n\n // Default action - capture handoff\n cmd\n .command('capture', { isDefault: true })\n .description('Commit current work and generate a handoff prompt')\n .option('-m, --message <message>', 'Custom commit message')\n .option('--no-commit', 'Skip git commit')\n .option('--copy', 'Copy the handoff prompt to clipboard')\n .option('--basic', 'Use basic handoff format instead of enhanced')\n .action(async (options) => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n // 1. Check git status\n let gitStatus = '';\n let hasChanges = false;\n\n try {\n gitStatus = execSync('git status --short', {\n encoding: 'utf-8',\n cwd: projectRoot,\n });\n hasChanges = gitStatus.trim().length > 0;\n } catch {\n console.log('\u26A0\uFE0F Not in a git repository');\n }\n\n // 2. Commit if there are changes and not skipped\n if (hasChanges && options.commit !== false) {\n try {\n // Get current branch\n const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n // Stage all changes\n execSync('git add -A', { cwd: projectRoot });\n\n // Generate or use custom commit message\n let commitMessage =\n options.message ||\n `chore: handoff checkpoint on ${currentBranch}`;\n\n // Validate commit message\n try {\n commitMessage = CommitMessageSchema.parse(commitMessage);\n } catch (validationError) {\n console.error(\n '\u274C Invalid commit message:',\n (validationError as Error).message\n );\n return;\n }\n\n // Commit using execFileSync for safety\n execFileSync('git', ['commit', '-m', commitMessage], {\n cwd: projectRoot,\n stdio: 'inherit',\n });\n\n console.log(`\u2705 Committed changes: \"${commitMessage}\"`);\n console.log(` Branch: ${currentBranch}`);\n } catch (err: unknown) {\n console.error(\n '\u274C Failed to commit changes:',\n (err as Error).message\n );\n }\n } else if (!hasChanges) {\n console.log('\u2139\uFE0F No changes to commit');\n }\n\n // 3. Gather context for handoff prompt\n let contextSummary = '';\n let tasksSummary = '';\n let recentWork = '';\n\n if (existsSync(dbPath)) {\n const db = new Database(dbPath);\n\n // Get recent context\n const frameManager = new FrameManager(db, 'cli-project');\n const activeFrames = frameManager.getActiveFramePath();\n\n if (activeFrames.length > 0) {\n contextSummary = 'Active context frames:\\n';\n activeFrames.forEach((frame) => {\n contextSummary += ` - ${frame.name} [${frame.type}]\\n`;\n });\n }\n\n // Get task status\n const taskStore = new LinearTaskManager(projectRoot, db);\n const activeTasks = taskStore.getActiveTasks();\n\n const inProgress = activeTasks.filter(\n (t: any) => t.status === 'in_progress'\n );\n const todo = activeTasks.filter((t: any) => t.status === 'pending');\n const recentlyCompleted = activeTasks\n .filter((t: any) => t.status === 'completed' && t.completed_at)\n .sort(\n (a: any, b: any) => (b.completed_at || 0) - (a.completed_at || 0)\n )\n .slice(0, 3);\n\n if (inProgress.length > 0 || todo.length > 0) {\n tasksSummary = '\\nTasks:\\n';\n\n if (inProgress.length > 0) {\n tasksSummary += 'In Progress:\\n';\n inProgress.forEach((t: any) => {\n const externalId = t.external_refs?.linear?.id;\n tasksSummary += ` - ${t.title}${externalId ? ` [${externalId}]` : ''}\\n`;\n });\n }\n\n if (todo.length > 0) {\n tasksSummary += 'TODO:\\n';\n todo.slice(0, 5).forEach((t: any) => {\n const externalId = t.external_refs?.linear?.id;\n tasksSummary += ` - ${t.title}${externalId ? ` [${externalId}]` : ''}\\n`;\n });\n if (todo.length > 5) {\n tasksSummary += ` ... and ${todo.length - 5} more\\n`;\n }\n }\n }\n\n if (recentlyCompleted.length > 0) {\n recentWork = '\\nRecently Completed:\\n';\n recentlyCompleted.forEach((t: any) => {\n recentWork += ` \u2713 ${t.title}\\n`;\n });\n }\n\n // Get recent events\n const recentEvents = db\n .prepare(\n `\n SELECT event_type as type, payload as data, datetime(ts, 'unixepoch') as time\n FROM events\n ORDER BY ts DESC\n LIMIT 5\n `\n )\n .all() as any[];\n\n if (recentEvents.length > 0) {\n recentWork += '\\nRecent Activity:\\n';\n recentEvents.forEach((event) => {\n const data = JSON.parse(event.data);\n recentWork += ` - ${event.type}: ${data.message || data.name || 'activity'}\\n`;\n });\n }\n\n db.close();\n }\n\n // 4. Get current git info\n let gitInfo = '';\n try {\n const branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n const lastCommit = execSync('git log -1 --oneline', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n gitInfo = `\\nGit Status:\\n Branch: ${branch}\\n Last commit: ${lastCommit}\\n`;\n } catch {\n // Ignore git errors\n }\n\n // 5. Check for any blockers or notes\n let notes = '';\n const notesPath = join(projectRoot, '.stackmemory', 'handoff.md');\n if (existsSync(notesPath)) {\n const handoffNotes = readFileSync(notesPath, 'utf-8');\n if (handoffNotes.trim()) {\n notes = `\\nNotes from previous handoff:\\n${handoffNotes}\\n`;\n }\n }\n\n // 6. Generate the handoff prompt\n let handoffPrompt: string;\n\n if (options.basic) {\n // Use basic handoff format\n const timestamp = new Date().toISOString();\n handoffPrompt = `# Session Handoff - ${timestamp}\n\n## Project: ${projectRoot.split('/').pop()}\n\n${gitInfo}\n${contextSummary}\n${tasksSummary}\n${recentWork}\n${notes}\n\n## Continue from here:\n\n1. Run \\`stackmemory status\\` to check the current state\n2. Review any in-progress tasks above\n3. Check for any uncommitted changes with \\`git status\\`\n4. Resume work on the active context\n\n## Quick Commands:\n- \\`stackmemory context load --recent\\` - Load recent context\n- \\`stackmemory task list --state in_progress\\` - Show in-progress tasks\n- \\`stackmemory linear sync\\` - Sync with Linear if configured\n- \\`stackmemory log recent\\` - View recent activity\n\n---\nGenerated by stackmemory handoff at ${timestamp}\n`;\n } else {\n // Use high-efficacy enhanced handoff generator (default)\n const enhancedGenerator = new EnhancedHandoffGenerator(projectRoot);\n const enhancedHandoff = await enhancedGenerator.generate();\n handoffPrompt = enhancedGenerator.toMarkdown(enhancedHandoff);\n console.log(`Estimated tokens: ~${enhancedHandoff.estimatedTokens}`);\n }\n\n // 7. Save handoff prompt (both latest and versioned)\n const stackmemoryDir = join(projectRoot, '.stackmemory');\n if (!existsSync(stackmemoryDir)) {\n mkdirSync(stackmemoryDir, { recursive: true });\n }\n const handoffPath = join(stackmemoryDir, 'last-handoff.md');\n writeFileSync(handoffPath, handoffPrompt);\n\n // Save versioned copy\n let branch = 'unknown';\n try {\n branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n } catch {\n // Not a git repo\n }\n const versionedPath = saveVersionedHandoff(\n projectRoot,\n branch,\n handoffPrompt\n );\n console.log(\n `Versioned: ${versionedPath.split('/').slice(-2).join('/')}`\n );\n\n // 8. Display the prompt\n console.log('\\n' + '='.repeat(60));\n console.log(handoffPrompt);\n console.log('='.repeat(60));\n\n // 9. Copy to clipboard if requested\n if (options.copy) {\n try {\n // Use execFileSync with predefined commands for safety\n if (process.platform === 'darwin') {\n execFileSync('pbcopy', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else if (process.platform === 'win32') {\n execFileSync('clip', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else {\n execFileSync('xclip', ['-selection', 'clipboard'], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n }\n\n console.log('\\n\u2705 Handoff prompt copied to clipboard!');\n } catch {\n console.log('\\n\u26A0\uFE0F Could not copy to clipboard');\n }\n }\n\n console.log(`\\n\uD83D\uDCBE Handoff saved to: ${handoffPath}`);\n console.log('\uD83D\uDCCB Use this prompt when starting your next session');\n } catch (error: unknown) {\n logger.error('Handoff command failed', error as Error);\n console.error('\u274C Handoff failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n // Restore command\n cmd\n .command('restore')\n .description('Restore context from last handoff')\n .option('--no-copy', 'Do not copy prompt to clipboard')\n .action(async (options) => {\n try {\n const projectRoot = process.cwd();\n const handoffPath = join(\n projectRoot,\n '.stackmemory',\n 'last-handoff.md'\n );\n const metaPath = join(\n process.env['HOME'] || '~',\n '.stackmemory',\n 'handoffs',\n 'last-handoff-meta.json'\n );\n\n if (!existsSync(handoffPath)) {\n console.log('\u274C No handoff found in this project');\n console.log('\uD83D\uDCA1 Run \"stackmemory handoff\" to create one');\n return;\n }\n\n // Read handoff prompt\n const handoffPrompt = readFileSync(handoffPath, 'utf-8');\n\n // Display the prompt\n console.log('\\n' + '='.repeat(60));\n console.log('\uD83D\uDCCB RESTORED HANDOFF');\n console.log('='.repeat(60));\n console.log(handoffPrompt);\n console.log('='.repeat(60));\n\n // Check for metadata\n if (existsSync(metaPath)) {\n const metadata = JSON.parse(readFileSync(metaPath, 'utf-8'));\n console.log('\\n\uD83D\uDCCA Session Metadata:');\n console.log(` Timestamp: ${metadata.timestamp}`);\n console.log(` Reason: ${metadata.reason}`);\n console.log(` Duration: ${metadata.session_duration}s`);\n console.log(` Command: ${metadata.command}`);\n }\n\n // Check current git status\n try {\n const gitStatus = execSync('git status --short', {\n encoding: 'utf-8',\n }).trim();\n if (gitStatus) {\n console.log('\\n\u26A0\uFE0F Current uncommitted changes:');\n console.log(gitStatus);\n }\n } catch {\n // Not a git repo\n }\n\n // Copy to clipboard unless disabled\n if (options.copy !== false) {\n try {\n // Use execFileSync with predefined commands for safety\n if (process.platform === 'darwin') {\n execFileSync('pbcopy', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else if (process.platform === 'win32') {\n execFileSync('clip', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else {\n execFileSync('xclip', ['-selection', 'clipboard'], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n }\n\n console.log('\\n\u2705 Handoff prompt copied to clipboard!');\n } catch {\n console.log('\\n\u26A0\uFE0F Could not copy to clipboard');\n }\n }\n\n console.log('\\n\uD83D\uDE80 Ready to continue where you left off!');\n } catch (error: unknown) {\n logger.error('Handoff restore failed', error as Error);\n console.error('\u274C Restore failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n // Auto command - enable auto-capture\n cmd\n .command('auto')\n .description('Enable auto-capture on session termination')\n .option('--command <command>', 'Command to wrap with auto-handoff')\n .action(async (options) => {\n const scriptPath = join(\n __dirname,\n '..',\n '..',\n '..',\n 'scripts',\n 'stackmemory-auto-handoff.sh'\n );\n\n if (!existsSync(scriptPath)) {\n console.error('\u274C Auto-handoff script not found');\n console.log('\uD83D\uDCE6 Please ensure StackMemory is properly installed');\n return;\n }\n\n console.log('\uD83D\uDEE1\uFE0F StackMemory Auto-Handoff');\n console.log('\u2500'.repeat(50));\n\n if (options.command) {\n // Validate and wrap specific command\n const commandSchema = z\n .string()\n .min(1, 'Command cannot be empty')\n .max(200, 'Command too long')\n .regex(\n /^[a-zA-Z0-9\\s\\-_./:]+$/,\n 'Command contains invalid characters'\n )\n .refine((cmd) => !cmd.includes(';'), 'Command cannot contain \";\"')\n .refine((cmd) => !cmd.includes('&'), 'Command cannot contain \"&\"')\n .refine((cmd) => !cmd.includes('|'), 'Command cannot contain \"|\"')\n .refine((cmd) => !cmd.includes('$'), 'Command cannot contain \"$\"')\n .refine((cmd) => !cmd.includes('`'), 'Command cannot contain \"`\"');\n\n try {\n const validatedCommand = commandSchema.parse(options.command);\n console.log(`Wrapping command: ${validatedCommand}`);\n execFileSync(scriptPath, [validatedCommand], {\n stdio: 'inherit',\n env: { ...process.env, AUTO_CAPTURE_ON_EXIT: 'true' },\n });\n } catch (validationError) {\n if (validationError instanceof z.ZodError) {\n console.error('\u274C Invalid command:');\n validationError.errors.forEach((err) => {\n console.error(` ${err.message}`);\n });\n } else {\n console.error(\n '\u274C Failed to execute command:',\n (validationError as Error).message\n );\n }\n return;\n }\n } else {\n // Interactive mode\n console.log('To enable auto-handoff for your current session:');\n console.log('');\n console.log(' For bash/zsh:');\n console.log(` source <(${scriptPath} --shell)`);\n console.log('');\n console.log(' Or wrap a command:');\n console.log(` ${scriptPath} claude`);\n console.log(` ${scriptPath} npm run dev`);\n console.log('');\n console.log(' Add to your shell profile for permanent setup:');\n console.log(\n ` echo 'alias claude=\"${scriptPath} claude\"' >> ~/.bashrc`\n );\n }\n });\n\n return cmd;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Handoff command - Commits work and generates a prompt for the next session\n */\n\nimport { Command } from 'commander';\nimport { execSync, execFileSync, spawn, ChildProcess } from 'child_process';\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n mkdirSync,\n readdirSync,\n unlinkSync,\n} from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport Database from 'better-sqlite3';\nimport { z } from 'zod';\nimport { FrameManager } from '../../core/context/index.js';\nimport { LinearTaskManager } from '../../features/tasks/linear-task-manager.js';\nimport { logger } from '../../core/monitoring/logger.js';\nimport { EnhancedHandoffGenerator } from '../../core/session/enhanced-handoff.js';\n\n// Handoff versioning - keep last N handoffs\nconst MAX_HANDOFF_VERSIONS = 10;\n\nfunction saveVersionedHandoff(\n projectRoot: string,\n branch: string,\n content: string\n): string {\n const handoffsDir = join(projectRoot, '.stackmemory', 'handoffs');\n if (!existsSync(handoffsDir)) {\n mkdirSync(handoffsDir, { recursive: true });\n }\n\n // Generate versioned filename: YYYY-MM-DD-HH-mm-branch.md\n const now = new Date();\n const timestamp = now.toISOString().slice(0, 16).replace(/[T:]/g, '-');\n const safeBranch = branch.replace(/[^a-zA-Z0-9-]/g, '-').slice(0, 30);\n const filename = `${timestamp}-${safeBranch}.md`;\n const versionedPath = join(handoffsDir, filename);\n\n // Save versioned handoff\n writeFileSync(versionedPath, content);\n\n // Clean up old handoffs (keep last N)\n try {\n const files = readdirSync(handoffsDir)\n .filter((f) => f.endsWith('.md'))\n .sort()\n .reverse();\n\n for (const oldFile of files.slice(MAX_HANDOFF_VERSIONS)) {\n unlinkSync(join(handoffsDir, oldFile));\n }\n } catch {\n // Cleanup failed, not critical\n }\n\n return versionedPath;\n}\n\n// Input validation schemas\nconst CommitMessageSchema = z\n .string()\n .min(1, 'Commit message cannot be empty')\n .max(200, 'Commit message too long')\n .regex(\n /^[a-zA-Z0-9\\s\\-_.,:()\\/\\[\\]]+$/,\n 'Commit message contains invalid characters'\n )\n .refine(\n (msg) => !msg.includes('\\n'),\n 'Commit message cannot contain newlines'\n )\n .refine(\n (msg) => !msg.includes('\"'),\n 'Commit message cannot contain double quotes'\n )\n .refine(\n (msg) => !msg.includes('`'),\n 'Commit message cannot contain backticks'\n );\n\nexport function createCaptureCommand(): Command {\n const cmd = new Command('capture');\n\n cmd\n .description('Commit current work and generate a handoff prompt')\n .option('-m, --message <message>', 'Custom commit message')\n .option('--no-commit', 'Skip git commit')\n .option('--copy', 'Copy the handoff prompt to clipboard')\n .option('--basic', 'Use basic handoff format instead of enhanced')\n .action(async (options) => {\n try {\n const projectRoot = process.cwd();\n const dbPath = join(projectRoot, '.stackmemory', 'context.db');\n\n // 1. Check git status\n let gitStatus = '';\n let hasChanges = false;\n\n try {\n gitStatus = execSync('git status --short', {\n encoding: 'utf-8',\n cwd: projectRoot,\n });\n hasChanges = gitStatus.trim().length > 0;\n } catch {\n console.log('\u26A0\uFE0F Not in a git repository');\n }\n\n // 2. Commit if there are changes and not skipped\n if (hasChanges && options.commit !== false) {\n try {\n // Get current branch\n const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n // Stage all changes\n execSync('git add -A', { cwd: projectRoot });\n\n // Generate or use custom commit message\n let commitMessage =\n options.message ||\n `chore: handoff checkpoint on ${currentBranch}`;\n\n // Validate commit message\n try {\n commitMessage = CommitMessageSchema.parse(commitMessage);\n } catch (validationError) {\n console.error(\n '\u274C Invalid commit message:',\n (validationError as Error).message\n );\n return;\n }\n\n // Commit using execFileSync for safety\n execFileSync('git', ['commit', '-m', commitMessage], {\n cwd: projectRoot,\n stdio: 'inherit',\n });\n\n console.log(`\u2705 Committed changes: \"${commitMessage}\"`);\n console.log(` Branch: ${currentBranch}`);\n } catch (err: unknown) {\n console.error(\n '\u274C Failed to commit changes:',\n (err as Error).message\n );\n }\n } else if (!hasChanges) {\n console.log('\u2139\uFE0F No changes to commit');\n }\n\n // 3. Gather context for handoff prompt\n let contextSummary = '';\n let tasksSummary = '';\n let recentWork = '';\n\n if (existsSync(dbPath)) {\n const db = new Database(dbPath);\n\n // Get recent context\n const frameManager = new FrameManager(db, 'cli-project');\n const activeFrames = frameManager.getActiveFramePath();\n\n if (activeFrames.length > 0) {\n contextSummary = 'Active context frames:\\n';\n activeFrames.forEach((frame) => {\n contextSummary += ` - ${frame.name} [${frame.type}]\\n`;\n });\n }\n\n // Get task status\n const taskStore = new LinearTaskManager(projectRoot, db);\n const activeTasks = taskStore.getActiveTasks();\n\n const inProgress = activeTasks.filter(\n (t: any) => t.status === 'in_progress'\n );\n const todo = activeTasks.filter((t: any) => t.status === 'pending');\n const recentlyCompleted = activeTasks\n .filter((t: any) => t.status === 'completed' && t.completed_at)\n .sort(\n (a: any, b: any) => (b.completed_at || 0) - (a.completed_at || 0)\n )\n .slice(0, 3);\n\n if (inProgress.length > 0 || todo.length > 0) {\n tasksSummary = '\\nTasks:\\n';\n\n if (inProgress.length > 0) {\n tasksSummary += 'In Progress:\\n';\n inProgress.forEach((t: any) => {\n const externalId = t.external_refs?.linear?.id;\n tasksSummary += ` - ${t.title}${externalId ? ` [${externalId}]` : ''}\\n`;\n });\n }\n\n if (todo.length > 0) {\n tasksSummary += 'TODO:\\n';\n todo.slice(0, 5).forEach((t: any) => {\n const externalId = t.external_refs?.linear?.id;\n tasksSummary += ` - ${t.title}${externalId ? ` [${externalId}]` : ''}\\n`;\n });\n if (todo.length > 5) {\n tasksSummary += ` ... and ${todo.length - 5} more\\n`;\n }\n }\n }\n\n if (recentlyCompleted.length > 0) {\n recentWork = '\\nRecently Completed:\\n';\n recentlyCompleted.forEach((t: any) => {\n recentWork += ` \u2713 ${t.title}\\n`;\n });\n }\n\n // Get recent events\n const recentEvents = db\n .prepare(\n `\n SELECT event_type as type, payload as data, datetime(ts, 'unixepoch') as time\n FROM events\n ORDER BY ts DESC\n LIMIT 5\n `\n )\n .all() as any[];\n\n if (recentEvents.length > 0) {\n recentWork += '\\nRecent Activity:\\n';\n recentEvents.forEach((event) => {\n const data = JSON.parse(event.data);\n recentWork += ` - ${event.type}: ${data.message || data.name || 'activity'}\\n`;\n });\n }\n\n db.close();\n }\n\n // 4. Get current git info\n let gitInfo = '';\n try {\n const branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n const lastCommit = execSync('git log -1 --oneline', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n\n gitInfo = `\\nGit Status:\\n Branch: ${branch}\\n Last commit: ${lastCommit}\\n`;\n } catch {\n // Ignore git errors\n }\n\n // 5. Check for any blockers or notes\n let notes = '';\n const notesPath = join(projectRoot, '.stackmemory', 'handoff.md');\n if (existsSync(notesPath)) {\n const handoffNotes = readFileSync(notesPath, 'utf-8');\n if (handoffNotes.trim()) {\n notes = `\\nNotes from previous handoff:\\n${handoffNotes}\\n`;\n }\n }\n\n // 6. Generate the handoff prompt\n let handoffPrompt: string;\n\n if (options.basic) {\n // Use basic handoff format\n const timestamp = new Date().toISOString();\n handoffPrompt = `# Session Handoff - ${timestamp}\n\n## Project: ${projectRoot.split('/').pop()}\n\n${gitInfo}\n${contextSummary}\n${tasksSummary}\n${recentWork}\n${notes}\n\n## Continue from here:\n\n1. Run \\`stackmemory status\\` to check the current state\n2. Review any in-progress tasks above\n3. Check for any uncommitted changes with \\`git status\\`\n4. Resume work on the active context\n\n## Quick Commands:\n- \\`stackmemory context load --recent\\` - Load recent context\n- \\`stackmemory task list --state in_progress\\` - Show in-progress tasks\n- \\`stackmemory linear sync\\` - Sync with Linear if configured\n- \\`stackmemory log recent\\` - View recent activity\n\n---\nGenerated by stackmemory capture at ${timestamp}\n`;\n } else {\n // Use high-efficacy enhanced handoff generator (default)\n const enhancedGenerator = new EnhancedHandoffGenerator(projectRoot);\n const enhancedHandoff = await enhancedGenerator.generate();\n handoffPrompt = enhancedGenerator.toMarkdown(enhancedHandoff);\n console.log(`Estimated tokens: ~${enhancedHandoff.estimatedTokens}`);\n }\n\n // 7. Save handoff prompt (both latest and versioned)\n const stackmemoryDir = join(projectRoot, '.stackmemory');\n if (!existsSync(stackmemoryDir)) {\n mkdirSync(stackmemoryDir, { recursive: true });\n }\n const handoffPath = join(stackmemoryDir, 'last-handoff.md');\n writeFileSync(handoffPath, handoffPrompt);\n\n // Save versioned copy\n let branch = 'unknown';\n try {\n branch = execSync('git rev-parse --abbrev-ref HEAD', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n } catch {\n // Not a git repo\n }\n const versionedPath = saveVersionedHandoff(\n projectRoot,\n branch,\n handoffPrompt\n );\n console.log(\n `Versioned: ${versionedPath.split('/').slice(-2).join('/')}`\n );\n\n // 8. Display the prompt\n console.log('\\n' + '='.repeat(60));\n console.log(handoffPrompt);\n console.log('='.repeat(60));\n\n // 9. Copy to clipboard if requested\n if (options.copy) {\n try {\n // Use execFileSync with predefined commands for safety\n if (process.platform === 'darwin') {\n execFileSync('pbcopy', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else if (process.platform === 'win32') {\n execFileSync('clip', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else {\n execFileSync('xclip', ['-selection', 'clipboard'], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n }\n\n console.log('\\n\u2705 Handoff prompt copied to clipboard!');\n } catch {\n console.log('\\n\u26A0\uFE0F Could not copy to clipboard');\n }\n }\n\n console.log(`\\n\uD83D\uDCBE Handoff saved to: ${handoffPath}`);\n console.log('\uD83D\uDCCB Use this prompt when starting your next session');\n } catch (error: unknown) {\n logger.error('Capture command failed', error as Error);\n console.error('\u274C Capture failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nexport function createRestoreCommand(): Command {\n const cmd = new Command('restore');\n\n cmd\n .description('Restore context from last handoff')\n .option('--no-copy', 'Do not copy prompt to clipboard')\n .action(async (options) => {\n try {\n const projectRoot = process.cwd();\n const handoffPath = join(\n projectRoot,\n '.stackmemory',\n 'last-handoff.md'\n );\n const metaPath = join(\n process.env['HOME'] || '~',\n '.stackmemory',\n 'handoffs',\n 'last-handoff-meta.json'\n );\n\n if (!existsSync(handoffPath)) {\n console.log('\u274C No handoff found in this project');\n console.log('\uD83D\uDCA1 Run \"stackmemory capture\" to create one');\n return;\n }\n\n // Read handoff prompt\n const handoffPrompt = readFileSync(handoffPath, 'utf-8');\n\n // Display the prompt\n console.log('\\n' + '='.repeat(60));\n console.log('\uD83D\uDCCB RESTORED HANDOFF');\n console.log('='.repeat(60));\n console.log(handoffPrompt);\n console.log('='.repeat(60));\n\n // Check for metadata\n if (existsSync(metaPath)) {\n const metadata = JSON.parse(readFileSync(metaPath, 'utf-8'));\n console.log('\\n\uD83D\uDCCA Session Metadata:');\n console.log(` Timestamp: ${metadata.timestamp}`);\n console.log(` Reason: ${metadata.reason}`);\n console.log(` Duration: ${metadata.session_duration}s`);\n console.log(` Command: ${metadata.command}`);\n }\n\n // Check current git status\n try {\n const gitStatus = execSync('git status --short', {\n encoding: 'utf-8',\n }).trim();\n if (gitStatus) {\n console.log('\\n\u26A0\uFE0F Current uncommitted changes:');\n console.log(gitStatus);\n }\n } catch {\n // Not a git repo\n }\n\n // Copy to clipboard unless disabled\n if (options.copy !== false) {\n try {\n // Use execFileSync with predefined commands for safety\n if (process.platform === 'darwin') {\n execFileSync('pbcopy', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else if (process.platform === 'win32') {\n execFileSync('clip', [], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n } else {\n execFileSync('xclip', ['-selection', 'clipboard'], {\n input: handoffPrompt,\n cwd: projectRoot,\n });\n }\n\n console.log('\\n\u2705 Handoff prompt copied to clipboard!');\n } catch {\n console.log('\\n\u26A0\uFE0F Could not copy to clipboard');\n }\n }\n\n console.log('\\n\uD83D\uDE80 Ready to continue where you left off!');\n } catch (error: unknown) {\n logger.error('Restore failed', error as Error);\n console.error('\u274C Restore failed:', (error as Error).message);\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\ninterface AutoCaptureMetadata {\n timestamp: string;\n reason: string;\n exit_code: number;\n command: string;\n pid: number;\n cwd: string;\n user: string;\n session_duration: number;\n}\n\nasync function captureHandoff(\n reason: string,\n exitCode: number,\n wrappedCommand: string,\n sessionStart: number,\n quiet: boolean\n): Promise<void> {\n const projectRoot = process.cwd();\n const handoffDir = join(homedir(), '.stackmemory', 'handoffs');\n const logFile = join(handoffDir, 'auto-handoff.log');\n\n // Ensure handoff directory exists\n if (!existsSync(handoffDir)) {\n mkdirSync(handoffDir, { recursive: true });\n }\n\n const logMessage = (msg: string): void => {\n const timestamp = new Date().toISOString().slice(0, 19).replace('T', ' ');\n const logLine = `[${timestamp}] ${msg}\\n`;\n try {\n writeFileSync(logFile, logLine, { flag: 'a' });\n } catch {\n // Logging failed, continue anyway\n }\n };\n\n if (!quiet) {\n console.log('\\nCapturing handoff context...');\n }\n logMessage(`Capturing handoff: reason=${reason}, exit_code=${exitCode}`);\n\n try {\n // Run stackmemory capture --no-commit\n execFileSync(\n process.execPath,\n [process.argv[1], 'capture', '--no-commit'],\n {\n cwd: projectRoot,\n stdio: quiet ? 'pipe' : 'inherit',\n }\n );\n\n // Save metadata\n const metadata: AutoCaptureMetadata = {\n timestamp: new Date().toISOString(),\n reason,\n exit_code: exitCode,\n command: wrappedCommand,\n pid: process.pid,\n cwd: projectRoot,\n user: process.env['USER'] || 'unknown',\n session_duration: Math.floor((Date.now() - sessionStart) / 1000),\n };\n\n const metadataPath = join(handoffDir, 'last-handoff-meta.json');\n writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));\n\n if (!quiet) {\n console.log('Handoff captured successfully');\n logMessage(`Handoff captured: ${metadataPath}`);\n\n // Show session summary\n console.log('\\nSession Summary:');\n console.log(` Duration: ${metadata.session_duration} seconds`);\n console.log(` Exit reason: ${reason}`);\n\n // Check for uncommitted changes\n try {\n const gitStatus = execSync('git status --short', {\n encoding: 'utf-8',\n cwd: projectRoot,\n }).trim();\n if (gitStatus) {\n console.log('\\nYou have uncommitted changes');\n console.log(' Run \"git status\" to review');\n }\n } catch {\n // Not a git repo or git not available\n }\n\n console.log('\\nRun \"stackmemory restore\" in your next session');\n }\n } catch (err) {\n if (!quiet) {\n console.error('Failed to capture handoff:', (err as Error).message);\n }\n logMessage(`ERROR: ${(err as Error).message}`);\n }\n}\n\nexport function createAutoCaptureCommand(): Command {\n const cmd = new Command('auto-capture');\n\n cmd\n .description('Wrap a command with automatic handoff capture on termination')\n .option('-a, --auto', 'Auto-capture on normal exit (no prompt)')\n .option('-q, --quiet', 'Suppress output')\n .option('-t, --tag <tag>', 'Tag this session')\n .argument('[command...]', 'Command to wrap with auto-handoff')\n .action(async (commandArgs: string[], options) => {\n const autoCapture = options.auto || false;\n const quiet = options.quiet || false;\n const tag = options.tag || '';\n\n // If no command provided, show usage\n if (!commandArgs || commandArgs.length === 0) {\n console.log('StackMemory Auto-Handoff');\n console.log('-'.repeat(50));\n console.log('');\n console.log(\n 'Wraps a command with automatic handoff capture on termination.'\n );\n console.log('');\n console.log('Usage:');\n console.log(' stackmemory auto-capture [options] <command> [args...]');\n console.log('');\n console.log('Examples:');\n console.log(' stackmemory auto-capture claude');\n console.log(' stackmemory auto-capture -a npm run dev');\n console.log(' stackmemory auto-capture -t \"feature-work\" vim');\n console.log('');\n console.log('Options:');\n console.log(\n ' -a, --auto Auto-capture on normal exit (no prompt)'\n );\n console.log(' -q, --quiet Suppress output');\n console.log(' -t, --tag <tag> Tag this session');\n return;\n }\n\n const wrappedCommand = commandArgs.join(' ');\n const sessionStart = Date.now();\n let capturedAlready = false;\n\n if (!quiet) {\n console.log('StackMemory Auto-Handoff Wrapper');\n console.log(`Wrapping: ${wrappedCommand}`);\n if (tag) {\n console.log(`Tag: ${tag}`);\n }\n console.log('Handoff will be captured on termination');\n console.log('');\n }\n\n // Spawn the wrapped command\n const [cmd, ...args] = commandArgs;\n let childProcess: ChildProcess;\n\n try {\n childProcess = spawn(cmd, args, {\n stdio: 'inherit',\n shell: false,\n cwd: process.cwd(),\n env: process.env,\n });\n } catch (err) {\n console.error(`Failed to start command: ${(err as Error).message}`);\n process.exit(1);\n return;\n }\n\n // Handle signals - forward to child and capture on termination\n const handleSignal = async (\n signal: NodeJS.Signals,\n exitCode: number\n ): Promise<void> => {\n if (capturedAlready) return;\n capturedAlready = true;\n\n if (!quiet) {\n console.log(`\\nReceived ${signal}`);\n }\n\n // Kill the child process if still running\n if (childProcess.pid && !childProcess.killed) {\n childProcess.kill(signal);\n }\n\n await captureHandoff(\n signal,\n exitCode,\n wrappedCommand,\n sessionStart,\n quiet\n );\n process.exit(exitCode);\n };\n\n process.on('SIGINT', () => handleSignal('SIGINT', 130));\n process.on('SIGTERM', () => handleSignal('SIGTERM', 143));\n process.on('SIGHUP', () => handleSignal('SIGHUP', 129));\n\n // Handle child process exit\n childProcess.on('exit', async (code, signal) => {\n if (capturedAlready) return;\n capturedAlready = true;\n\n const exitCode = code ?? (signal ? 128 : 0);\n\n if (signal) {\n // Child was killed by a signal\n await captureHandoff(\n signal,\n exitCode,\n wrappedCommand,\n sessionStart,\n quiet\n );\n } else if (exitCode !== 0) {\n // Unexpected exit\n if (!quiet) {\n console.log(`\\nCommand exited with code: ${exitCode}`);\n }\n await captureHandoff(\n 'unexpected_exit',\n exitCode,\n wrappedCommand,\n sessionStart,\n quiet\n );\n } else if (autoCapture) {\n // Normal exit with auto-capture enabled\n await captureHandoff(\n 'normal_exit',\n 0,\n wrappedCommand,\n sessionStart,\n quiet\n );\n } else {\n // Normal exit - prompt for capture (simplified for CLI, auto-capture)\n // In non-interactive contexts, default to capturing\n if (process.stdin.isTTY) {\n // Interactive - we could prompt but keeping it simple\n console.log(\n '\\nSession ending. Use -a flag for auto-capture on normal exit.'\n );\n }\n }\n\n process.exit(exitCode);\n });\n\n // Handle spawn errors\n childProcess.on('error', async (err) => {\n if (capturedAlready) return;\n capturedAlready = true;\n\n console.error(`Command error: ${err.message}`);\n await captureHandoff(\n 'spawn_error',\n 1,\n wrappedCommand,\n sessionStart,\n quiet\n );\n process.exit(1);\n });\n });\n\n return cmd;\n}\n\n/** @deprecated Use createCaptureCommand, createRestoreCommand, createAutoCaptureCommand */\nexport function createHandoffCommand(): Command {\n const cmd = new Command('handoff');\n cmd.description('(deprecated) Use \"capture\" or \"restore\" instead');\n return cmd;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["branch", "cmd"]
|
|
7
7
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -24,7 +24,11 @@ import { createSearchCommand } from "./commands/search.js";
|
|
|
24
24
|
import { createLogCommand } from "./commands/log.js";
|
|
25
25
|
import { createContextCommands } from "./commands/context.js";
|
|
26
26
|
import { createConfigCommand } from "./commands/config.js";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
createCaptureCommand,
|
|
29
|
+
createRestoreCommand,
|
|
30
|
+
createAutoCaptureCommand
|
|
31
|
+
} from "./commands/handoff.js";
|
|
28
32
|
import {
|
|
29
33
|
createDecisionCommand,
|
|
30
34
|
createMemoryCommand
|
|
@@ -506,7 +510,9 @@ program.addCommand(createSearchCommand());
|
|
|
506
510
|
program.addCommand(createLogCommand());
|
|
507
511
|
program.addCommand(createContextCommands());
|
|
508
512
|
program.addCommand(createConfigCommand());
|
|
509
|
-
program.addCommand(
|
|
513
|
+
program.addCommand(createCaptureCommand());
|
|
514
|
+
program.addCommand(createRestoreCommand());
|
|
515
|
+
program.addCommand(createAutoCaptureCommand());
|
|
510
516
|
program.addCommand(createDecisionCommand());
|
|
511
517
|
program.addCommand(createMemoryCommand());
|
|
512
518
|
program.addCommand(clearCommand);
|