diff --git a/home/dot_hammerspoon/executable_git-sync.sh b/home/dot_hammerspoon/executable_git-sync.sh new file mode 100644 index 0000000..423bb22 --- /dev/null +++ b/home/dot_hammerspoon/executable_git-sync.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +REPO_PATH="$1" +REMOTE_NAME="$2" +COMMIT_MESSAGE_TEMPLATE="$3" + +cd "$REPO_PATH" || { + echo "Error: Cannot access repository at $REPO_PATH" + exit 1 +} + +if ! git rev-parse --git-dir > /dev/null 2>&1; then + echo "Error: Not a git repository" + exit 1 +fi + +sync_repo() { + echo "Starting git sync for $(pwd)" + + # Check if there are any changes to commit + if [[ -n $(git status --porcelain) ]]; then + echo "Changes detected, committing..." + COMMIT_MESSAGE=$(eval echo "\"$COMMIT_MESSAGE_TEMPLATE\"") + git add . + git commit -m "$COMMIT_MESSAGE" + if [[ $? -eq 0 ]]; then + echo "Changes committed successfully" + else + echo "Error committing changes" + return 1 + fi + else + echo "No changes to commit" + fi + + # Fetch and pull from remote + echo "Fetching from remote..." + git fetch "$REMOTE_NAME" + if [[ $? -eq 0 ]]; then + echo "Pulling changes..." + git pull "$REMOTE_NAME" $(git branch --show-current) --rebase + if [[ $? -eq 0 ]]; then + echo "Pull completed successfully" + else + echo "Error during pull" + return 1 + fi + else + echo "Error fetching from remote" + return 1 + fi + + # Push to remote + echo "Pushing to remote..." + git push "$REMOTE_NAME" $(git branch --show-current) + if [[ $? -eq 0 ]]; then + echo "Push completed successfully" + else + echo "Error during push" + return 1 + fi + + echo "Git sync completed successfully" +} + +sync_repo diff --git a/home/dot_hammerspoon/init.lua.tmpl b/home/dot_hammerspoon/init.lua.tmpl new file mode 100644 index 0000000..2b02dc6 --- /dev/null +++ b/home/dot_hammerspoon/init.lua.tmpl @@ -0,0 +1,156 @@ +local preloadView = hs.webview.new({x=0, y=0, w=10, h=10}):html("") +preloadView:hide() +hs.timer.doAfter(2, function() preloadView:delete() end) -- delete after 2 seconds + +local GitSync = {} + +GitSync.config = { + repoPath = "/Users/matthew.dillon/notebook", + remoteName = "pingo", + syncInterval = 60, + commitMessage = "Auto-sync: $(date +\"%Y-%m-%d %H:%M:%S\") from $(hostname)" +} + +GitSync.scriptPath = os.getenv("HOME") .. "/.hammerspoon/git-sync.sh" + +GitSync.timer = nil + +GitSync.caffeineWatcher = nil + +function GitSync.runSync(reason) + reason = reason or "periodic" + print("Git sync triggered: " .. reason) + + local task = hs.task.new(GitSync.scriptPath, function(exitCode, stdOut, stdErr) + if exitCode == 0 then + print("Git sync completed successfully (" .. reason .. ")") + if stdOut and stdOut ~= "" then + print("Output: " .. stdOut) + end + else + print("Git sync failed (" .. reason .. ") with exit code: " .. exitCode) + if stdErr and stdErr ~= "" then + print("Error: " .. stdErr) + end + end + end, { + GitSync.config.repoPath, + GitSync.config.remoteName, + GitSync.config.commitMessage + }) + + task:start() +end + +function GitSync.startPeriodicSync() + if GitSync.timer then + GitSync.timer:stop() + end + + GitSync.timer = hs.timer.doEvery(GitSync.config.syncInterval, function() + GitSync.runSync("periodic") + end) + + print("Git periodic sync started (interval: " .. GitSync.config.syncInterval .. " seconds)") +end + +function GitSync.stopPeriodicSync() + if GitSync.timer then + GitSync.timer:stop() + GitSync.timer = nil + print("Git periodic sync stopped") + end +end + +function GitSync.handlePowerEvent(eventType) + if eventType == hs.caffeinate.watcher.systemWillSleep then + print("System going to sleep, running git sync...") + GitSync.runSync("pre-sleep") + elseif eventType == hs.caffeinate.watcher.systemDidWake then + print("System woke up, running git sync...") + -- Add a small delay to ensure network is available + hs.timer.doAfter(5, function() + GitSync.runSync("post-wake") + end) + end +end + +function GitSync.startPowerEventMonitoring() + GitSync.caffeineWatcher = hs.caffeinate.watcher.new(GitSync.handlePowerEvent) + GitSync.caffeineWatcher:start() + print("Git power event monitoring started") +end + +function GitSync.stopPowerEventMonitoring() + if GitSync.caffeineWatcher then + GitSync.caffeineWatcher:stop() + GitSync.caffeineWatcher = nil + print("Git power event monitoring stopped") + end +end + +function GitSync.start() + GitSync.startPeriodicSync() + GitSync.startPowerEventMonitoring() + + GitSync.runSync("initial") + + print("Git auto-sync initialized") + print("Repository: " .. GitSync.config.repoPath) + print("Remote: " .. GitSync.config.remoteName) + print("Sync interval: " .. GitSync.config.syncInterval .. " seconds") +end + +function GitSync.stop() + GitSync.stopPeriodicSync() + GitSync.stopPowerEventMonitoring() + print("Git auto-sync stopped") +end + +GitSync.start() + +if hs.menubar then + GitSync.menubar = hs.menubar.new() + GitSync.menubar:setTitle("🦖") + GitSync.menubar:setTooltip("Git Auto-Sync") + GitSync.menubar:setMenu({ + { title = "Sync Now", fn = function() GitSync.runSync("manual") end }, + { title = "Start Auto-Sync", fn = GitSync.start }, + { title = "Stop Auto-Sync", fn = GitSync.stop }, + { title = "-" }, + { title = "Repository: " .. GitSync.config.repoPath, disabled = true } + }) +end + +-- Make GitSync available globally for console access +_G.GitSync = GitSync + +local filePath = "/Users/matthew.dillon/notebook/inbox.md" + +hs.hotkey.bind({"cmd", "shift"}, "J", function() + local button, text = hs.dialog.textPrompt( + "Add To-Do", + "Enter your tasks (one per line):", + "", + "OK", + "Cancel" + ) + if button == "OK" and text ~= "" then + -- Split input into lines + local lines = {} + for line in text:gmatch("[^\r\n]+") do + table.insert(lines, "- [ ] " .. line) + end + -- Concatenate lines with newlines + local formatted = table.concat(lines, "\n") .. "\n" + -- Append to file + local file = io.open(filePath, "a") + if file then + file:write(formatted) + file:close() + hs.alert.show("Tasks added!") + else + hs.alert.show("Failed to open file.") + end + end +end) diff --git a/home/dot_zshrc.tmpl b/home/dot_zshrc.tmpl index 09679c2..0978f0a 100644 --- a/home/dot_zshrc.tmpl +++ b/home/dot_zshrc.tmpl @@ -65,8 +65,8 @@ alias devlog="cd ~/projects/personal/devlog && hx logs/$(date '+%Y-%m-%d').gmi & eval "$(/opt/homebrew/bin/brew shellenv)" eval "$(direnv hook zsh)" eval "$(jj util completion zsh)" -export NVM_DIR="$HOME/.nvm" -[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" +# export NVM_DIR="$HOME/.nvm" +# [ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh" [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" function reldate() { @@ -83,3 +83,87 @@ export FZF_DEFAULT_OPTS=" \ --color=marker:#b4befe,fg+:#cdd6f4,prompt:#cba6f7,hl+:#f38ba8 \ --color=selected-bg:#45475a \ --color=border:#313244,label:#cdd6f4" + +task_inbox_count_prompt() { + local count + count=$(task +inbox +PENDING count 2>/dev/null) + if [[ $count -gt 0 ]]; then + echo "%B%F{yellow}(inbox:$count)%f%b " + fi +} + +select_project() { + local project_list result query selection project + + project_list=$(task _unique project | grep -v '^$') + result=$(echo "$project_list" | fzf --prompt="select project: " --print-query --expect=enter) + + query=$(echo "$result" | sed -n 1p) + key=$(echo "$result" | sed -n 2p) + selection=$(echo "$result" | sed -n 3p) + + if [ -z "$selection" ]; then + project="$query" + else + project="$selection" + fi + + if [ -z "$project" ] || [ "$project" = "enter" ]; then + return 1 + fi + + echo "$project" +} + +work_on() { + if [ -z "$1" ]; then + echo "usage: work_on " + return 1 + fi + + task "$1" start + + description=$(task _get "$1".description) + + klog switch -s "$description" + if [ $? -ne 0 ]; then + klog start -s "$description" + fi +} + +task_file() { + if [ -z "$1" ]; then + echo "usage: task_file " + return 1 + fi + + task "$1" modify -inbox project:"$(select_project)" +} + +task_schedule() { + if [ -z "$1" ]; then + echo "usage: task_schedule []" + return 1 + fi + + local id="$1" + local date="$2" + + if [ -n "$date" ]; then + task "$id" modify scheduled:"$date" + return + fi + + local current_scheduled + current_scheduled=$(task "$id" _get scheduled) + + if [ -z "$current_scheduled" ]; then + task "$id" modify scheduled:today + else + task "$id" modify scheduled: + fi +} + +export PS1=' +$(task_inbox_count_prompt)%(!.%B%F{red}%n%f%b in .${SSH_TTY:+"%B%F{yellow}%n%f%b in "})${SSH_TTY:+"%B%F{green}%m%f%b in "}%B%F{cyan}%~%f%b${(e)git_info[prompt]}${VIRTUAL_ENV:+" via %B%F{yellow}${VIRTUAL_ENV:t}%f%b"}${duration_info} +%B%(1j.%F{blue}*%f .)%(?.%F{green}.%F{red}%? )$(_prompt_asciiship_vimode)%f%b ' diff --git a/home/private_dot_config/jj/config.toml.tmpl b/home/private_dot_config/jj/config.toml.tmpl index f70bc32..737c147 100644 --- a/home/private_dot_config/jj/config.toml.tmpl +++ b/home/private_dot_config/jj/config.toml.tmpl @@ -3,9 +3,11 @@ name = {{ .name | quote }} email = {{ .email_personal | quote }} [git] -push-bookmark-prefix = "{{ .github_personal }}_jj_" private-commits = "description(glob:'private:*') | bookmarks('merge')" +[templates] +git_push_bookmark = '"{{ .github_personal }}_jj_" ++ change_id.short()' + [colors] "diff removed token" = { fg = "red", underline = false } "diff added token" = { fg = "green", underline = false } @@ -22,5 +24,5 @@ diff-formatter = ":git" --when.repositories = ["~/Klaviyo", "~/.klaviyocli"] [--scope.user] email = {{ .email_work | quote }} -[--scope.git] -push-bookmark-prefix = "2025_{{ .github_work }}_jj_" +[--scope.templates] +git_push_bookmark = '"2025_{{ .github_work }}_jj_" ++ change_id.short()' diff --git a/home/private_dot_config/task/taskrc.tmpl b/home/private_dot_config/task/taskrc.tmpl index aa598e3..9534dea 100644 --- a/home/private_dot_config/task/taskrc.tmpl +++ b/home/private_dot_config/task/taskrc.tmpl @@ -1,18 +1,31 @@ data.location={{ .chezmoi.homeDir }}/.task news.version=3.4.1 +default.command=act +alias.next=next limit:1 +alias.log=add +inbox +alias.inbox=list project: +inbox + # must be specified bc taskrc not in default ~/.taskrc location data.location=~/.local/share/task hooks.location=~/.config/task/hooks include solarized-dark-256.theme -report.list.columns=id,start.age,depends.indicator,priority,project,tags,recur.indicator,scheduled.countdown,due,until.remaining,description.count -report.list.labels=id,active,d,p,project,tags,r,sch,due,until,description +report.list.columns=id,start.age,depends.indicator,priority,project,tags,recur.indicator,scheduled,due,until.remaining,description.count +report.list.labels=id,active,deps,pri,proj,tags,recur,sched,due,until,desc -report.next.columns=id,start.age,depends,priority,project,tags,recur,scheduled.countdown,due.relative,until.remaining,description -report.next.labels=id,active,deps,p,project,tag,recur,s,due,until,description +report.act.description=unblocked tasks +report.act.columns=id,start.age,depends,priority,project,tags,recur,scheduled,due,until.remaining,description.count +report.act.labels=id,active,deps,pri,proj,tags,recur,sched,due,until,desc +report.act.filter=status:pending -WAITING -BLOCKED -inbox +report.act.sort=project+/,due+,entry+ sync.server.url={{ .task_url }} sync.server.client_id={{ .task_client_id }} sync.encryption_secret={{ .task_encryption_secret }} + +uda.estimate.type=numeric +uda.estimate.label=estimated_hrs + +context.work.read=-personal