@towles/tool 0.0.108 → 0.0.110
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/package.json +9 -4
- package/{plugins/tt-agentboard → packages/agentboard}/README.md +1 -1
- package/{plugins/tt-agentboard → packages/agentboard}/apps/server/package.json +2 -1
- package/{plugins/tt-agentboard → packages/agentboard}/apps/server/src/main.ts +6 -20
- package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/package.json +4 -0
- package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/components/DetailPanel.tsx +3 -2
- package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/components/StatusBar.tsx +35 -0
- package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/constants.ts +1 -0
- package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/index.tsx +204 -225
- package/packages/agentboard/apps/tui/src/session-status.test.ts +70 -0
- package/packages/agentboard/apps/tui/src/session-status.ts +19 -0
- package/{plugins/tt-agentboard → packages/agentboard}/package.json +2 -6
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/package.json +3 -0
- package/{plugins/tt-agentboard/packages/runtime/test → packages/agentboard/packages/runtime/src/agents}/tracker.test.ts +2 -2
- package/packages/agentboard/packages/runtime/src/agents/watchers/claude-code.test.ts +63 -0
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/agents/watchers/claude-code.ts +26 -2
- package/packages/agentboard/packages/runtime/src/config.test.ts +107 -0
- package/packages/agentboard/packages/runtime/src/config.ts +80 -0
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/index.ts +1 -1
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/plugins/loader.ts +1 -33
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/git-info.ts +3 -2
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/index.ts +23 -37
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/launcher.ts +6 -18
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/pane-scanner.ts +6 -0
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/shared.ts +2 -0
- package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/tsconfig.json +1 -1
- package/{plugins/tt-core → packages/core}/.claude-plugin/plugin.json +1 -1
- package/packages/shared/package.json +15 -0
- package/packages/shared/src/git/exec.ts +41 -0
- package/{src/utils → packages/shared/src}/git/gh-cli-wrapper.ts +13 -18
- package/packages/shared/src/index.ts +8 -0
- package/packages/shared/tsconfig.json +16 -0
- package/src/cli.ts +3 -2
- package/src/commands/agentboard.ts +42 -59
- package/src/{lib → commands}/auto-claude/claude-cli.ts +1 -1
- package/src/commands/auto-claude/config-init-helpers.ts +79 -0
- package/src/commands/auto-claude/config-init.test.ts +137 -0
- package/src/commands/auto-claude/config-init.ts +159 -0
- package/src/{lib → commands}/auto-claude/config.ts +4 -8
- package/src/{lib → commands}/auto-claude/e2e.test.ts +6 -6
- package/src/commands/auto-claude/explain.test.ts +58 -0
- package/src/commands/auto-claude/explain.ts +97 -0
- package/src/commands/auto-claude/index.ts +37 -14
- package/src/{lib → commands}/auto-claude/labels.ts +1 -1
- package/src/commands/auto-claude/list.ts +5 -4
- package/src/{lib → commands}/auto-claude/pipeline-execution.test.ts +1 -1
- package/src/{lib → commands}/auto-claude/pipeline.ts +1 -3
- package/src/commands/auto-claude/retry.test.ts +2 -2
- package/src/commands/auto-claude/retry.ts +5 -5
- package/src/commands/auto-claude/shell.ts +3 -0
- package/src/commands/auto-claude/status.test.ts +2 -2
- package/src/commands/auto-claude/status.ts +4 -4
- package/src/{lib → commands}/auto-claude/steps/create-pr.ts +1 -3
- package/src/{lib → commands}/auto-claude/steps/fetch-issues.ts +1 -1
- package/src/{lib → commands}/auto-claude/steps/implement.ts +1 -2
- package/src/{lib → commands}/auto-claude/utils-execution.test.ts +6 -6
- package/src/{lib → commands}/auto-claude/utils.ts +10 -4
- package/src/{lib/install → commands}/claude-settings.ts +1 -1
- package/src/commands/config/config.test.ts +129 -0
- package/src/commands/config/index.ts +11 -0
- package/src/commands/config/reset.ts +53 -0
- package/src/commands/config/schema.ts +19 -0
- package/src/commands/{config.ts → config/show.ts} +2 -2
- package/src/commands/config/validate.ts +51 -0
- package/src/commands/doctor/checks.ts +167 -0
- package/src/commands/doctor/format.test.ts +63 -0
- package/src/commands/doctor/format.ts +5 -0
- package/src/commands/doctor/history.test.ts +161 -0
- package/src/commands/doctor/history.ts +130 -0
- package/src/commands/doctor.ts +80 -151
- package/src/commands/gh/branch-clean.ts +4 -4
- package/src/commands/gh/branch.test.ts +4 -5
- package/src/commands/gh/branch.ts +10 -5
- package/src/commands/gh/pr.ts +6 -7
- package/src/{lib → commands}/graph/analyzer.test.ts +4 -4
- package/src/commands/graph/format.test.ts +130 -0
- package/src/commands/graph/format.ts +94 -0
- package/src/commands/graph/index.ts +69 -41
- package/src/{lib → commands}/graph/labels.ts +4 -4
- package/src/{lib → commands}/graph/server.ts +2 -2
- package/src/{lib → commands}/graph/types.ts +2 -0
- package/src/commands/graph.test.ts +1 -1
- package/src/commands/install.ts +6 -6
- package/src/commands/journal/daily-notes.ts +4 -7
- package/src/{lib → commands}/journal/fs.ts +1 -1
- package/src/commands/journal/index.ts +2 -0
- package/src/commands/journal/list.test.ts +174 -0
- package/src/commands/journal/list.ts +213 -0
- package/src/commands/journal/meeting.ts +4 -7
- package/src/commands/journal/note.ts +4 -7
- package/src/{lib → commands}/journal/paths.ts +1 -1
- package/src/commands/journal/search.test.ts +156 -0
- package/src/commands/journal/search.ts +256 -0
- package/src/{lib → commands}/journal/templates.ts +1 -1
- package/src/config/settings.ts +35 -26
- package/plugins/tt-agentboard/bun.lock +0 -444
- package/plugins/tt-agentboard/packages/runtime/src/config.ts +0 -70
- package/plugins/tt-agentboard/packages/runtime/test/config.test.ts +0 -83
- package/plugins/tt-auto-claude/.claude-plugin/plugin.json +0 -8
- package/plugins/tt-auto-claude/commands/create-issue.md +0 -20
- package/plugins/tt-auto-claude/commands/list.md +0 -21
- package/plugins/tt-auto-claude/skills/auto-claude/SKILL.md +0 -71
- package/plugins/tt-core/promptfooconfig.interview-me.yaml +0 -155
- package/plugins/tt-core/promptfooconfig.refine-text.yaml +0 -242
- package/plugins/tt-core/promptfooconfig.tdd.yaml +0 -144
- package/plugins/tt-core/promptfooconfig.write-prd.yaml +0 -145
- package/src/commands/config.test.ts +0 -9
- package/src/lib/auto-claude/index.ts +0 -15
- package/src/lib/auto-claude/shell.ts +0 -6
- package/src/lib/graph/index.ts +0 -24
- package/src/lib/journal/index.ts +0 -11
- package/src/utils/git/exec.ts +0 -18
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/build.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/bunfig.toml +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/scripts/sessionizer.sh +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/components/DiffStats.tsx +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/components/SessionCard.tsx +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/detail-panel-height.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/src/mux-context.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/apps/tui/tsconfig.json +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/mux-tmux/package.json +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/mux-tmux/src/client.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/mux-tmux/src/index.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/mux-tmux/src/provider.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/mux-tmux/tsconfig.json +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/agents/tracker.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/agents/watchers/amp.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/agents/watchers/codex.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/agents/watchers/opencode.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/contracts/agent-watcher.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/contracts/agent.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/contracts/index.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/contracts/mux.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/debug.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/mux/detect.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/mux/registry.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/context.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/metadata-store.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/port-scanner.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/session-order.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/sidebar-manager.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/server/sidebar-width-sync.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/packages/runtime/src/themes.ts +0 -0
- /package/{plugins/tt-agentboard → packages/agentboard}/tsconfig.json +0 -0
- /package/{plugins/tt-core → packages/core}/README.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/improve-architecture.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/interview-me.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/prd-to-issues.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/refine-text.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/task.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/tdd.md +0 -0
- /package/{plugins/tt-core → packages/core}/commands/write-prd.md +0 -0
- /package/{plugins/tt-core → packages/core}/skills/towles-tool/SKILL.md +0 -0
- /package/{src/utils → packages/shared/src}/date-utils.test.ts +0 -0
- /package/{src/utils → packages/shared/src}/date-utils.ts +0 -0
- /package/{src/utils → packages/shared/src}/fs.ts +0 -0
- /package/{src/utils → packages/shared/src}/git/branch-name.test.ts +0 -0
- /package/{src/utils → packages/shared/src}/git/branch-name.ts +0 -0
- /package/{src/utils → packages/shared/src}/git/gh-cli-wrapper.test.ts +0 -0
- /package/{src/utils → packages/shared/src}/render.test.ts +0 -0
- /package/{src/utils → packages/shared/src}/render.ts +0 -0
- /package/src/{lib → commands}/auto-claude/config.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/labels.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/pipeline.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/01_plan.prompt.md +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/02_implement.prompt.md +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/03_simplify.prompt.md +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/04_review.prompt.md +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/CLAUDE.md +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/index.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/prompt-templates/index.ts +0 -0
- /package/src/{lib → commands}/auto-claude/run-claude.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/spawn-claude.ts +0 -0
- /package/src/{lib → commands}/auto-claude/steps/simple-steps.ts +0 -0
- /package/src/{lib → commands}/auto-claude/steps/steps.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/stream-parser.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/stream-parser.ts +0 -0
- /package/src/{lib → commands}/auto-claude/templates.test.ts +0 -0
- /package/src/{lib → commands}/auto-claude/templates.ts +0 -0
- /package/src/{lib → commands}/auto-claude/test-helpers.ts +0 -0
- /package/src/{lib → commands}/auto-claude/utils.test.ts +0 -0
- /package/src/{lib → commands}/graph/analyzer.ts +0 -0
- /package/src/{lib → commands}/graph/graph-template.html +0 -0
- /package/src/{lib → commands}/graph/parser.test.ts +0 -0
- /package/src/{lib → commands}/graph/parser.ts +0 -0
- /package/src/{lib → commands}/graph/render.ts +0 -0
- /package/src/{lib → commands}/graph/sessions.ts +0 -0
- /package/src/{lib → commands}/graph/tools.ts +0 -0
- /package/src/{lib → commands}/graph/treemap.ts +0 -0
- /package/src/{lib → commands}/journal/editor.ts +0 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
import consola from "consola";
|
|
6
|
+
import { colors } from "consola/utils";
|
|
7
|
+
import { withSettings, debugArg } from "../shared.js";
|
|
8
|
+
import type { JournalType } from "../../types/journal.js";
|
|
9
|
+
import { JOURNAL_TYPES } from "../../types/journal.js";
|
|
10
|
+
|
|
11
|
+
export interface SearchMatch {
|
|
12
|
+
filePath: string;
|
|
13
|
+
lineNumber: number;
|
|
14
|
+
line: string;
|
|
15
|
+
context: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SearchOptions {
|
|
19
|
+
query: string;
|
|
20
|
+
type?: JournalType;
|
|
21
|
+
startDate?: Date;
|
|
22
|
+
endDate?: Date;
|
|
23
|
+
contextLines?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Recursively collect all .md files under a directory.
|
|
28
|
+
*/
|
|
29
|
+
export function collectMarkdownFiles(dir: string): string[] {
|
|
30
|
+
const results: string[] = [];
|
|
31
|
+
let entries: string[];
|
|
32
|
+
try {
|
|
33
|
+
entries = readdirSync(dir);
|
|
34
|
+
} catch {
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
const full = path.join(dir, entry);
|
|
39
|
+
let stat;
|
|
40
|
+
try {
|
|
41
|
+
stat = statSync(full);
|
|
42
|
+
} catch {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (stat.isDirectory()) {
|
|
46
|
+
results.push(...collectMarkdownFiles(full));
|
|
47
|
+
} else if (entry.endsWith(".md")) {
|
|
48
|
+
results.push(full);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return results;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Determine journal type from a file path based on directory names.
|
|
56
|
+
*/
|
|
57
|
+
export function inferTypeFromPath(filePath: string): JournalType | null {
|
|
58
|
+
const lower = filePath.toLowerCase();
|
|
59
|
+
if (lower.includes("/daily-notes/") || lower.includes("daily-notes")) {
|
|
60
|
+
return JOURNAL_TYPES.DAILY_NOTES;
|
|
61
|
+
}
|
|
62
|
+
if (lower.includes("/meetings/") || lower.includes("/meeting/")) {
|
|
63
|
+
return JOURNAL_TYPES.MEETING;
|
|
64
|
+
}
|
|
65
|
+
if (lower.includes("/notes/") || lower.includes("/note/")) {
|
|
66
|
+
return JOURNAL_TYPES.NOTE;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Extract a date from a filename like `2026-03-15-*.md`.
|
|
73
|
+
* Returns null if no date pattern is found.
|
|
74
|
+
*/
|
|
75
|
+
export function extractDateFromFilename(filePath: string): Date | null {
|
|
76
|
+
const basename = path.basename(filePath);
|
|
77
|
+
const match = basename.match(/^(\d{4})-(\d{2})-(\d{2})/);
|
|
78
|
+
if (!match) return null;
|
|
79
|
+
const [, year, month, day] = match;
|
|
80
|
+
return new Date(Number(year), Number(month) - 1, Number(day));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Search journal files for a query string, returning matches with context.
|
|
85
|
+
*/
|
|
86
|
+
export function searchJournalFiles(files: string[], options: SearchOptions): SearchMatch[] {
|
|
87
|
+
const { query, type, startDate, endDate, contextLines = 2 } = options;
|
|
88
|
+
const lowerQuery = query.toLowerCase();
|
|
89
|
+
const matches: SearchMatch[] = [];
|
|
90
|
+
|
|
91
|
+
for (const filePath of files) {
|
|
92
|
+
// Filter by type
|
|
93
|
+
if (type) {
|
|
94
|
+
const fileType = inferTypeFromPath(filePath);
|
|
95
|
+
if (fileType !== type) continue;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Filter by date range
|
|
99
|
+
if (startDate || endDate) {
|
|
100
|
+
const fileDate = extractDateFromFilename(filePath);
|
|
101
|
+
if (fileDate) {
|
|
102
|
+
if (startDate && fileDate < startDate) continue;
|
|
103
|
+
if (endDate && fileDate > endDate) continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let content: string;
|
|
108
|
+
try {
|
|
109
|
+
content = readFileSync(filePath, "utf8");
|
|
110
|
+
} catch {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const lines = content.split("\n");
|
|
115
|
+
for (let i = 0; i < lines.length; i++) {
|
|
116
|
+
if (lines[i].toLowerCase().includes(lowerQuery)) {
|
|
117
|
+
const ctxStart = Math.max(0, i - contextLines);
|
|
118
|
+
const ctxEnd = Math.min(lines.length - 1, i + contextLines);
|
|
119
|
+
const context: string[] = [];
|
|
120
|
+
for (let j = ctxStart; j <= ctxEnd; j++) {
|
|
121
|
+
const prefix = j === i ? ">" : " ";
|
|
122
|
+
context.push(`${prefix} ${j + 1}: ${lines[j]}`);
|
|
123
|
+
}
|
|
124
|
+
matches.push({
|
|
125
|
+
filePath,
|
|
126
|
+
lineNumber: i + 1,
|
|
127
|
+
line: lines[i],
|
|
128
|
+
context,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return matches;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Parse a date range string like `2026-01-01..2026-03-01`.
|
|
139
|
+
*/
|
|
140
|
+
export function parseDateRange(range: string): { startDate: Date; endDate: Date } {
|
|
141
|
+
const parts = range.split("..");
|
|
142
|
+
if (parts.length !== 2) {
|
|
143
|
+
throw new Error(`Invalid date range format: "${range}". Expected: YYYY-MM-DD..YYYY-MM-DD`);
|
|
144
|
+
}
|
|
145
|
+
const [startStr, endStr] = parts;
|
|
146
|
+
const startDate = new Date(startStr);
|
|
147
|
+
const endDate = new Date(endStr);
|
|
148
|
+
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
|
|
149
|
+
throw new TypeError(`Invalid dates in range: "${range}". Expected: YYYY-MM-DD..YYYY-MM-DD`);
|
|
150
|
+
}
|
|
151
|
+
return { startDate, endDate };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const VALID_TYPES = new Set<string>([
|
|
155
|
+
JOURNAL_TYPES.DAILY_NOTES,
|
|
156
|
+
JOURNAL_TYPES.MEETING,
|
|
157
|
+
JOURNAL_TYPES.NOTE,
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
export default defineCommand({
|
|
161
|
+
meta: {
|
|
162
|
+
name: "search",
|
|
163
|
+
description: "Search journal entries for matching text",
|
|
164
|
+
},
|
|
165
|
+
args: {
|
|
166
|
+
debug: debugArg,
|
|
167
|
+
query: {
|
|
168
|
+
type: "positional",
|
|
169
|
+
required: true,
|
|
170
|
+
description: "Text to search for",
|
|
171
|
+
},
|
|
172
|
+
type: {
|
|
173
|
+
type: "string",
|
|
174
|
+
alias: "t",
|
|
175
|
+
description: "Filter by entry type: daily-notes, meeting, note",
|
|
176
|
+
},
|
|
177
|
+
range: {
|
|
178
|
+
type: "string",
|
|
179
|
+
alias: "r",
|
|
180
|
+
description: "Filter by date range: YYYY-MM-DD..YYYY-MM-DD",
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
async run({ args }) {
|
|
184
|
+
const { settings } = await withSettings(args.debug);
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const baseFolder = settings.journalSettings.baseFolder;
|
|
188
|
+
const journalDir = path.join(baseFolder, "journal");
|
|
189
|
+
|
|
190
|
+
// Validate --type
|
|
191
|
+
let typeFilter: JournalType | undefined;
|
|
192
|
+
if (args.type) {
|
|
193
|
+
if (!VALID_TYPES.has(args.type)) {
|
|
194
|
+
consola.error(
|
|
195
|
+
`Invalid type "${args.type}". Must be one of: ${[...VALID_TYPES].join(", ")}`,
|
|
196
|
+
);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
typeFilter = args.type as JournalType;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Parse --range
|
|
203
|
+
let startDate: Date | undefined;
|
|
204
|
+
let endDate: Date | undefined;
|
|
205
|
+
if (args.range) {
|
|
206
|
+
const parsed = parseDateRange(args.range);
|
|
207
|
+
startDate = parsed.startDate;
|
|
208
|
+
endDate = parsed.endDate;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const files = collectMarkdownFiles(journalDir);
|
|
212
|
+
if (files.length === 0) {
|
|
213
|
+
consola.info(`No journal files found in ${colors.cyan(journalDir)}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const matches = searchJournalFiles(files, {
|
|
218
|
+
query: args.query,
|
|
219
|
+
type: typeFilter,
|
|
220
|
+
startDate,
|
|
221
|
+
endDate,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
if (matches.length === 0) {
|
|
225
|
+
consola.info(`No matches found for "${colors.cyan(args.query)}"`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
consola.info(
|
|
230
|
+
`Found ${colors.green(String(matches.length))} match(es) for "${colors.cyan(args.query)}":\n`,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Group matches by file
|
|
234
|
+
const byFile = new Map<string, SearchMatch[]>();
|
|
235
|
+
for (const m of matches) {
|
|
236
|
+
const existing = byFile.get(m.filePath) ?? [];
|
|
237
|
+
existing.push(m);
|
|
238
|
+
byFile.set(m.filePath, existing);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
for (const [filePath, fileMatches] of byFile) {
|
|
242
|
+
const relative = path.relative(baseFolder, filePath);
|
|
243
|
+
console.log(colors.bold(colors.cyan(relative)));
|
|
244
|
+
for (const m of fileMatches) {
|
|
245
|
+
for (const line of m.context) {
|
|
246
|
+
console.log(line);
|
|
247
|
+
}
|
|
248
|
+
console.log("");
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
consola.error(`Search failed:`, error);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
});
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import consola from "consola";
|
|
4
4
|
import { colors } from "consola/utils";
|
|
5
|
-
import { formatDate, getWeekInfo } from "
|
|
5
|
+
import { formatDate, getWeekInfo } from "@towles/shared";
|
|
6
6
|
import { ensureDirectoryExists } from "./fs.js";
|
|
7
7
|
|
|
8
8
|
// Default template file names
|
package/src/config/settings.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
|
-
import
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import consola from "consola";
|
|
@@ -36,11 +36,33 @@ export const JournalSettingsSchema = z.object({
|
|
|
36
36
|
|
|
37
37
|
export type JournalSettings = z.infer<typeof JournalSettingsSchema>;
|
|
38
38
|
|
|
39
|
+
export const AgentboardSettingsSchema = z.object({
|
|
40
|
+
mux: z.string().optional(),
|
|
41
|
+
port: z.number().optional(),
|
|
42
|
+
theme: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),
|
|
43
|
+
sidebarWidth: z.number().optional(),
|
|
44
|
+
sidebarPosition: z.enum(["left", "right"]).optional(),
|
|
45
|
+
keybinding: z.string().optional(),
|
|
46
|
+
detailPanelHeights: z.record(z.string(), z.number()).optional(),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export type AgentboardSettings = z.infer<typeof AgentboardSettingsSchema>;
|
|
50
|
+
|
|
39
51
|
export const UserSettingsSchema = z.object({
|
|
40
52
|
preferredEditor: z.string().default("code"),
|
|
41
53
|
journalSettings: JournalSettingsSchema.optional().transform(
|
|
42
54
|
(v) => v ?? JournalSettingsSchema.parse({}),
|
|
43
55
|
),
|
|
56
|
+
agentboard: AgentboardSettingsSchema.optional().transform(
|
|
57
|
+
(v) => v ?? AgentboardSettingsSchema.parse({}),
|
|
58
|
+
),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** Schema without transforms — safe for JSON Schema export */
|
|
62
|
+
export const UserSettingsRawSchema = z.object({
|
|
63
|
+
preferredEditor: z.string().default("code"),
|
|
64
|
+
journalSettings: JournalSettingsSchema.optional(),
|
|
65
|
+
agentboard: AgentboardSettingsSchema.optional(),
|
|
44
66
|
});
|
|
45
67
|
|
|
46
68
|
type UserSettings = z.infer<typeof UserSettingsSchema>;
|
|
@@ -54,24 +76,20 @@ function createDefaultSettings(): UserSettings {
|
|
|
54
76
|
return UserSettingsSchema.parse({});
|
|
55
77
|
}
|
|
56
78
|
|
|
57
|
-
function createAndSaveDefaultSettings(): UserSettings {
|
|
79
|
+
async function createAndSaveDefaultSettings(): Promise<UserSettings> {
|
|
58
80
|
const userSettings = createDefaultSettings();
|
|
59
|
-
saveSettings({
|
|
81
|
+
await saveSettings({
|
|
60
82
|
path: USER_SETTINGS_PATH,
|
|
61
83
|
settings: userSettings,
|
|
62
84
|
});
|
|
63
85
|
return userSettings;
|
|
64
86
|
}
|
|
65
87
|
|
|
66
|
-
export function saveSettings(settingsFile: SettingsFile): void {
|
|
88
|
+
export async function saveSettings(settingsFile: SettingsFile): Promise<void> {
|
|
67
89
|
try {
|
|
68
|
-
// Ensure the directory exists
|
|
69
90
|
const dirPath = path.dirname(settingsFile.path);
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
fs.writeFileSync(settingsFile.path, JSON.stringify(settingsFile.settings, null, 2), "utf-8");
|
|
91
|
+
await mkdir(dirPath, { recursive: true });
|
|
92
|
+
await writeFile(settingsFile.path, JSON.stringify(settingsFile.settings, null, 2), "utf-8");
|
|
75
93
|
} catch (error) {
|
|
76
94
|
consola.error("Error saving user settings file:", error);
|
|
77
95
|
}
|
|
@@ -80,32 +98,23 @@ export function saveSettings(settingsFile: SettingsFile): void {
|
|
|
80
98
|
export async function loadSettings(): Promise<SettingsFile> {
|
|
81
99
|
let userSettings: UserSettings | null = null;
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const userContent = fs.readFileSync(USER_SETTINGS_PATH, "utf-8");
|
|
101
|
+
try {
|
|
102
|
+
const userContent = await readFile(USER_SETTINGS_PATH, "utf-8");
|
|
86
103
|
const parsedUserSettings: unknown = JSON.parse(userContent);
|
|
87
104
|
|
|
88
105
|
userSettings = UserSettingsSchema.parse(parsedUserSettings);
|
|
89
|
-
// made add a save here if the default values differ from the current values
|
|
90
106
|
if (JSON.stringify(parsedUserSettings) !== JSON.stringify(userSettings)) {
|
|
91
107
|
consola.warn(`Settings file ${USER_SETTINGS_PATH} has been updated with default values.`);
|
|
92
|
-
|
|
93
|
-
path: USER_SETTINGS_PATH,
|
|
94
|
-
settings: userSettings,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
saveSettings(tempSettingsFile);
|
|
108
|
+
await saveSettings({ path: USER_SETTINGS_PATH, settings: userSettings });
|
|
98
109
|
}
|
|
99
|
-
}
|
|
100
|
-
// Settings file doesn't exist
|
|
110
|
+
} catch {
|
|
111
|
+
// Settings file doesn't exist — create it
|
|
101
112
|
const isNonInteractive = process.env.CI || !process.stdout.isTTY;
|
|
102
113
|
|
|
103
114
|
if (isNonInteractive) {
|
|
104
|
-
// Auto-create in CI/non-TTY environments
|
|
105
115
|
consola.info(`Creating settings file: ${USER_SETTINGS_PATH}`);
|
|
106
|
-
userSettings = createAndSaveDefaultSettings();
|
|
116
|
+
userSettings = await createAndSaveDefaultSettings();
|
|
107
117
|
} else {
|
|
108
|
-
// Interactive: ask user if they want to create it
|
|
109
118
|
const confirmed = await consola.prompt(
|
|
110
119
|
`Settings file not found. Create ${colors.cyan(USER_SETTINGS_PATH)}?`,
|
|
111
120
|
{
|
|
@@ -115,7 +124,7 @@ export async function loadSettings(): Promise<SettingsFile> {
|
|
|
115
124
|
if (!confirmed) {
|
|
116
125
|
throw new Error(`Settings file not found and user chose not to create it.`);
|
|
117
126
|
}
|
|
118
|
-
userSettings = createAndSaveDefaultSettings();
|
|
127
|
+
userSettings = await createAndSaveDefaultSettings();
|
|
119
128
|
}
|
|
120
129
|
}
|
|
121
130
|
|