@towles/tool 0.0.41 → 0.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +67 -109
  2. package/package.json +51 -41
  3. package/src/commands/base.ts +3 -18
  4. package/src/commands/config.ts +9 -8
  5. package/src/commands/doctor.ts +4 -1
  6. package/src/commands/gh/branch-clean.ts +10 -4
  7. package/src/commands/gh/branch.ts +6 -3
  8. package/src/commands/gh/pr.ts +10 -3
  9. package/src/commands/graph-template.html +1214 -0
  10. package/src/commands/graph.test.ts +176 -0
  11. package/src/commands/graph.ts +970 -0
  12. package/src/commands/install.ts +8 -2
  13. package/src/commands/journal/daily-notes.ts +9 -5
  14. package/src/commands/journal/meeting.ts +12 -6
  15. package/src/commands/journal/note.ts +12 -6
  16. package/src/commands/ralph/plan/add.ts +75 -0
  17. package/src/commands/ralph/plan/done.ts +82 -0
  18. package/src/commands/ralph/{task → plan}/list.test.ts +5 -5
  19. package/src/commands/ralph/{task → plan}/list.ts +28 -39
  20. package/src/commands/ralph/plan/remove.ts +71 -0
  21. package/src/commands/ralph/run.test.ts +521 -0
  22. package/src/commands/ralph/run.ts +126 -189
  23. package/src/commands/ralph/show.ts +88 -0
  24. package/src/config/settings.ts +8 -27
  25. package/src/{commands/ralph/lib → lib/ralph}/execution.ts +4 -14
  26. package/src/lib/ralph/formatter.ts +238 -0
  27. package/src/{commands/ralph/lib → lib/ralph}/state.ts +17 -42
  28. package/src/utils/date-utils.test.ts +2 -1
  29. package/src/utils/date-utils.ts +2 -2
  30. package/LICENSE.md +0 -20
  31. package/src/commands/index.ts +0 -55
  32. package/src/commands/observe/graph.test.ts +0 -89
  33. package/src/commands/observe/graph.ts +0 -1640
  34. package/src/commands/observe/report.ts +0 -166
  35. package/src/commands/observe/session.ts +0 -385
  36. package/src/commands/observe/setup.ts +0 -180
  37. package/src/commands/observe/status.ts +0 -146
  38. package/src/commands/ralph/lib/formatter.ts +0 -298
  39. package/src/commands/ralph/lib/marker.ts +0 -108
  40. package/src/commands/ralph/marker/create.ts +0 -23
  41. package/src/commands/ralph/plan.ts +0 -73
  42. package/src/commands/ralph/progress.ts +0 -44
  43. package/src/commands/ralph/ralph.test.ts +0 -673
  44. package/src/commands/ralph/task/add.ts +0 -105
  45. package/src/commands/ralph/task/done.ts +0 -73
  46. package/src/commands/ralph/task/remove.ts +0 -62
  47. package/src/config/context.ts +0 -7
  48. package/src/constants.ts +0 -3
  49. package/src/utils/anthropic/types.ts +0 -158
  50. package/src/utils/exec.ts +0 -8
  51. package/src/utils/git/git.ts +0 -25
  52. /package/src/{commands → lib}/journal/utils.ts +0 -0
  53. /package/src/{commands/ralph/lib → lib/ralph}/index.ts +0 -0
@@ -1,108 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { homedir } from "node:os";
4
- import * as readline from "node:readline";
5
-
6
- // ============================================================================
7
- // Constants
8
- // ============================================================================
9
-
10
- export const MARKER_PREFIX = "RALPH_MARKER_";
11
- const CLAUDE_DIR = path.join(homedir(), ".claude");
12
- const PROJECTS_DIR = path.join(CLAUDE_DIR, "projects");
13
-
14
- // ============================================================================
15
- // Marker Generation
16
- // ============================================================================
17
-
18
- /**
19
- * Generate a random marker string (8 chars alphanumeric)
20
- */
21
- export function generateMarker(): string {
22
- const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
23
- let result = "";
24
- for (let i = 0; i < 8; i++) {
25
- result += chars.charAt(Math.floor(Math.random() * chars.length));
26
- }
27
- return result;
28
- }
29
-
30
- // ============================================================================
31
- // Session Search
32
- // ============================================================================
33
-
34
- /**
35
- * Get the project directory path for the current working directory
36
- */
37
- function getProjectDir(): string | null {
38
- const cwd = process.cwd();
39
- // Claude stores projects with path separators replaced by dashes
40
- const projectName = cwd.replace(/\//g, "-");
41
- const projectDir = path.join(PROJECTS_DIR, projectName);
42
-
43
- if (fs.existsSync(projectDir)) {
44
- return projectDir;
45
- }
46
- return null;
47
- }
48
-
49
- /**
50
- * Search for a marker in session files and return the session ID.
51
- * Expects the full marker (e.g., RALPH_MARKER_abc123).
52
- */
53
- export async function findSessionByMarker(marker: string): Promise<string | null> {
54
- const projectDir = getProjectDir();
55
- if (!projectDir) {
56
- return null;
57
- }
58
-
59
- // Get all .jsonl files in the project directory
60
- const files = fs
61
- .readdirSync(projectDir)
62
- .filter((f) => f.endsWith(".jsonl"))
63
- .map((f) => ({
64
- name: f,
65
- path: path.join(projectDir, f),
66
- mtime: fs.statSync(path.join(projectDir, f)).mtime.getTime(),
67
- }))
68
- // Sort by most recent first
69
- .sort((a, b) => b.mtime - a.mtime);
70
-
71
- for (const file of files) {
72
- const found = await searchFileForMarker(file.path, marker);
73
- if (found) {
74
- // Session ID is the filename without .jsonl
75
- return file.name.replace(".jsonl", "");
76
- }
77
- }
78
-
79
- return null;
80
- }
81
-
82
- /**
83
- * Search a single file for the marker (streaming to handle large files)
84
- */
85
- async function searchFileForMarker(filePath: string, marker: string): Promise<boolean> {
86
- return new Promise((resolve) => {
87
- const stream = fs.createReadStream(filePath, { encoding: "utf8" });
88
- const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
89
-
90
- let found = false;
91
-
92
- rl.on("line", (line) => {
93
- if (line.includes(marker)) {
94
- found = true;
95
- rl.close();
96
- stream.destroy();
97
- }
98
- });
99
-
100
- rl.on("close", () => {
101
- resolve(found);
102
- });
103
-
104
- rl.on("error", () => {
105
- resolve(false);
106
- });
107
- });
108
- }
@@ -1,23 +0,0 @@
1
- import { BaseCommand } from "../../base.js";
2
- import { generateMarker, MARKER_PREFIX } from "../lib/marker.js";
3
-
4
- /**
5
- * Generate a random marker for session tracking.
6
- * Output this marker during research, then use --findMarker when adding tasks.
7
- */
8
- export default class MarkerCreate extends BaseCommand {
9
- static override description = "Generate a random marker for session tracking";
10
-
11
- static override examples = ["<%= config.bin %> ralph marker create"];
12
-
13
- static override flags = {
14
- ...BaseCommand.baseFlags,
15
- };
16
-
17
- async run(): Promise<void> {
18
- await this.parse(MarkerCreate);
19
-
20
- const marker = generateMarker();
21
- console.log(`${MARKER_PREFIX}${marker}`);
22
- }
23
- }
@@ -1,73 +0,0 @@
1
- import { Flags } from "@oclif/core";
2
- import pc from "picocolors";
3
- import { BaseCommand } from "../base.js";
4
- import { DEFAULT_STATE_FILE, loadState, resolveRalphPath } from "./lib/state.js";
5
- import { formatPlanAsMarkdown, formatPlanAsJson, copyToClipboard } from "./lib/formatter.js";
6
-
7
- /**
8
- * Show plan summary with status, tasks, and mermaid graph
9
- */
10
- export default class Plan extends BaseCommand {
11
- static override description = "Show plan summary with status, tasks, and mermaid graph";
12
-
13
- static override examples = [
14
- "<%= config.bin %> ralph plan",
15
- "<%= config.bin %> ralph plan --format json",
16
- "<%= config.bin %> ralph plan --copy",
17
- ];
18
-
19
- static override flags = {
20
- ...BaseCommand.baseFlags,
21
- stateFile: Flags.string({
22
- char: "s",
23
- description: `State file path (default: ${DEFAULT_STATE_FILE})`,
24
- }),
25
- format: Flags.string({
26
- char: "f",
27
- description: "Output format",
28
- default: "default",
29
- options: ["default", "markdown", "json"],
30
- }),
31
- copy: Flags.boolean({
32
- description: "Copy output to clipboard",
33
- default: false,
34
- }),
35
- };
36
-
37
- async run(): Promise<void> {
38
- const { flags } = await this.parse(Plan);
39
- const ralphSettings = this.settings.settingsFile.settings.ralphSettings;
40
- const stateFile = resolveRalphPath(flags.stateFile, "stateFile", ralphSettings);
41
-
42
- const state = loadState(stateFile);
43
-
44
- if (!state) {
45
- console.log(pc.yellow(`No state file found at: ${stateFile}`));
46
- return;
47
- }
48
-
49
- if (state.tasks.length === 0) {
50
- console.log(pc.yellow("No tasks in state file."));
51
- console.log(pc.dim('Use: tt ralph task add "description"'));
52
- return;
53
- }
54
-
55
- let output: string;
56
-
57
- if (flags.format === "json") {
58
- output = formatPlanAsJson(state.tasks, state);
59
- } else {
60
- output = formatPlanAsMarkdown(state.tasks, state);
61
- }
62
-
63
- console.log(output);
64
-
65
- if (flags.copy) {
66
- if (copyToClipboard(output)) {
67
- console.log(pc.green("✓ Copied to clipboard"));
68
- } else {
69
- console.log(pc.yellow("⚠ Could not copy to clipboard (xclip/xsel not installed?)"));
70
- }
71
- }
72
- }
73
- }
@@ -1,44 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { Args, Flags } from "@oclif/core";
4
- import { BaseCommand } from "../base.js";
5
- import { DEFAULT_PROGRESS_FILE, resolveRalphPath } from "./lib/state.js";
6
-
7
- /**
8
- * Append progress message to ralph-progress.md (write-only, no read)
9
- */
10
- export default class Progress extends BaseCommand {
11
- static override description = "Append progress message (write-only, never reads file)";
12
-
13
- static override examples = [
14
- '<%= config.bin %> ralph progress "Completed user service implementation"',
15
- '<%= config.bin %> ralph progress "Starting tests" --file custom-progress.md',
16
- ];
17
-
18
- static override args = {
19
- message: Args.string({
20
- description: "Progress message to append",
21
- required: true,
22
- }),
23
- };
24
-
25
- static override flags = {
26
- ...BaseCommand.baseFlags,
27
- file: Flags.string({
28
- char: "f",
29
- description: `Progress file path (default: ${DEFAULT_PROGRESS_FILE})`,
30
- }),
31
- };
32
-
33
- async run(): Promise<void> {
34
- const { args, flags } = await this.parse(Progress);
35
- const ralphSettings = this.settings.settingsFile.settings.ralphSettings;
36
- const progressFile = resolveRalphPath(flags.file, "progressFile", ralphSettings);
37
-
38
- const timestamp = new Date().toISOString();
39
- const line = `- [${timestamp}] ${args.message}\n`;
40
-
41
- fs.mkdirSync(path.dirname(progressFile), { recursive: true });
42
- fs.appendFileSync(progressFile, line);
43
- }
44
- }