Compare commits
9
Commits
fccb75298e
...
75dcd21776
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75dcd21776 | ||
|
|
94a1925f1b | ||
|
|
623117d6c5 | ||
|
|
ab12436d07 | ||
|
|
79a4040b0a | ||
|
|
43952188ad | ||
|
|
1a1ba1131c | ||
|
|
312bfd18be | ||
|
|
8c8a352945 |
@@ -141,6 +141,12 @@ EOF
|
|||||||
|
|
||||||
An effort task is the same call with `--projects '[[atribot]]'`, no actor tag, and `--prop git_branch=…` when the work is not on main.
|
An effort task is the same call with `--projects '[[atribot]]'`, no actor tag, and `--prop git_branch=…` when the work is not on main.
|
||||||
|
|
||||||
|
Efforts and tickets are worked from the frontier, not a calendar, so none carries a scheduled date. The plugin stamps `date_scheduled: <today>` on every task it creates, and `tn` cannot suppress or clear it — empty `--scheduled` values are dropped by both `create` and `update`. Strip it right after each create:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
obsidian property:remove name=date_scheduled path='TaskNotes/Dev/atribot/Network isolation/Split obsync into its own container.md'
|
||||||
|
```
|
||||||
|
|
||||||
Create in dependency order so a blocker's title exists before the ticket naming it. Flag reference: `tasknotes-cli`.
|
Create in dependency order so a blocker's title exists before the ticket naming it. Flag reference: `tasknotes-cli`.
|
||||||
|
|
||||||
A second `--blocked-by` does not add a second blocker — the flag is read once, so every blocker goes in one comma-separated value as above. Commas inside `[[...]]` are literal, so titles containing commas are safe.
|
A second `--blocked-by` does not add a second blocker — the flag is read once, so every blocker goes in one comma-separated value as above. Commas inside `[[...]]` are literal, so titles containing commas are safe.
|
||||||
@@ -274,6 +280,8 @@ tn list --filter 'projects:contains:"[[Network isolation]]" AND dependencies.isB
|
|||||||
- **`tn update`** for everything TaskNotes models — status, priority, dates, estimate, tags, contexts, projects, `blockedBy` — and all queries. It goes through the update service, which maintains `date_modified` and recurring-instance bookkeeping.
|
- **`tn update`** for everything TaskNotes models — status, priority, dates, estimate, tags, contexts, projects, `blockedBy` — and all queries. It goes through the update service, which maintains `date_modified` and recurring-instance bookkeeping.
|
||||||
- **`obsidian`** for what `tn update` has no flag for: custom properties after creation (`agent_session`, `git_branch`, `git_worktree`) and body text. `obsidian property:set` writes YAML directly and skips the update service.
|
- **`obsidian`** for what `tn update` has no flag for: custom properties after creation (`agent_session`, `git_branch`, `git_worktree`) and body text. `obsidian property:set` writes YAML directly and skips the update service.
|
||||||
|
|
||||||
|
In a sandboxed session, invoke `obsidian` only as a simple or `&&`-chained command. The command is the Obsidian AppImage, and the sandbox denies its FUSE mount when the call sits inside a shell loop — every iteration fails with `fuse: device not found`. Write a batch over many notes as chained single calls, not a loop.
|
||||||
|
|
||||||
Mid-flight dependency edits are rare, since blockers are written at creation. When one is needed:
|
Mid-flight dependency edits are rare, since blockers are written at creation. When one is needed:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@@ -1,8 +0,0 @@
|
|||||||
#/bin/bash
|
|
||||||
|
|
||||||
podman run --rm -i \
|
|
||||||
-v ${HOME}/Music:/downloads:z \
|
|
||||||
--userns keep-id:uid=1000,gid=1000 \
|
|
||||||
--entrypoint scdl \
|
|
||||||
yt-dlp:latest $@
|
|
||||||
|
|
||||||
+10
-4
@@ -64,7 +64,11 @@ fi
|
|||||||
alias tmux="tmux -2"
|
alias tmux="tmux -2"
|
||||||
alias grep="grep --color=auto"
|
alias grep="grep --color=auto"
|
||||||
|
|
||||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
if command -v brew >/dev/null 2>&1; then
|
||||||
|
eval "$(brew shellenv)"
|
||||||
|
elif [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then
|
||||||
|
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||||
|
fi
|
||||||
|
|
||||||
# Fix gpg signing
|
# Fix gpg signing
|
||||||
# https://github.com/keybase/keybase-issues/issues/2798
|
# https://github.com/keybase/keybase-issues/issues/2798
|
||||||
@@ -78,8 +82,8 @@ export TERM="xterm-256color"
|
|||||||
export EDITOR=$(which nvim)
|
export EDITOR=$(which nvim)
|
||||||
|
|
||||||
# Adding applications to path
|
# Adding applications to path
|
||||||
if [[ -d ${HOME}/.dotfiles/bin/linux ]]; then
|
if [[ -d ${HOME}/.local/bin ]] && [[ ":${PATH}:" != *":${HOME}/.local/bin:"* ]]; then
|
||||||
export PATH=$PATH:${HOME}/.dotfiles/bin/linux
|
export PATH=${HOME}/.local/bin:${PATH}
|
||||||
fi
|
fi
|
||||||
if [[ -d ${HOME}/bin ]]; then
|
if [[ -d ${HOME}/bin ]]; then
|
||||||
export PATH=$PATH:${HOME}/bin
|
export PATH=$PATH:${HOME}/bin
|
||||||
@@ -88,7 +92,9 @@ fi
|
|||||||
|
|
||||||
# Enable atuin
|
# Enable atuin
|
||||||
# https://docs.atuin.sh
|
# https://docs.atuin.sh
|
||||||
eval "$(atuin init bash)"
|
if command -v atuin >/dev/null 2>&1; then
|
||||||
|
eval "$(atuin init bash)"
|
||||||
|
fi
|
||||||
|
|
||||||
# fzf
|
# fzf
|
||||||
#eval "$(fzf --bash)"
|
#eval "$(fzf --bash)"
|
||||||
|
|||||||
+50
-13
@@ -33,7 +33,31 @@
|
|||||||
],
|
],
|
||||||
"defaultMode": "auto"
|
"defaultMode": "auto"
|
||||||
},
|
},
|
||||||
|
"model": "opus[1m]",
|
||||||
|
"disableClaudeAiConnectors": true,
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "atuin hook claude-code"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PostToolUseFailure": [
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "atuin hook claude-code"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"PreToolUse": [
|
"PreToolUse": [
|
||||||
{
|
{
|
||||||
"matcher": "Bash",
|
"matcher": "Bash",
|
||||||
@@ -47,22 +71,33 @@
|
|||||||
"command": "~/.claude/hooks/block-file-deletion.sh"
|
"command": "~/.claude/hooks/block-file-deletion.sh"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": "Bash",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "atuin hook claude-code"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"disableWorkflows": true,
|
||||||
|
"disableArtifact": true,
|
||||||
"statusLine": {
|
"statusLine": {
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "bash /home/tgrosinger/.claude/statusline-command.sh"
|
"command": "bash /home/tgrosinger/.claude/statusline-command.sh"
|
||||||
},
|
},
|
||||||
"enabledPlugins": {
|
"enabledPlugins": {
|
||||||
"pr-review-toolkit@claude-plugins-official": true,
|
|
||||||
"gopls-lsp@claude-plugins-official": true,
|
|
||||||
"frontend-design@claude-plugins-official": true,
|
|
||||||
"code-simplifier@claude-plugins-official": true,
|
|
||||||
"skill-creator@claude-plugins-official": true,
|
|
||||||
"typescript-lsp@claude-plugins-official": true,
|
|
||||||
"claude-md-management@claude-plugins-official": true,
|
"claude-md-management@claude-plugins-official": true,
|
||||||
"security-guidance@claude-plugins-official": true
|
"code-simplifier@claude-plugins-official": true,
|
||||||
|
"frontend-design@claude-plugins-official": true,
|
||||||
|
"gopls-lsp@claude-plugins-official": true,
|
||||||
|
"pr-review-toolkit@claude-plugins-official": true,
|
||||||
|
"security-guidance@claude-plugins-official": true,
|
||||||
|
"skill-creator@claude-plugins-official": true,
|
||||||
|
"typescript-lsp@claude-plugins-official": true
|
||||||
},
|
},
|
||||||
"sandbox": {
|
"sandbox": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
@@ -86,19 +121,23 @@
|
|||||||
"filesystem": {
|
"filesystem": {
|
||||||
"allowWrite": [
|
"allowWrite": [
|
||||||
"~/.local/share/pnpm",
|
"~/.local/share/pnpm",
|
||||||
"~/.cache/pnpm"
|
"~/.cache/pnpm",
|
||||||
|
"~/Documents/Atrium"
|
||||||
],
|
],
|
||||||
"denyRead": [
|
"denyRead": [
|
||||||
"~/.ssh",
|
"~/.ssh",
|
||||||
"~/.config/Signal",
|
"~/.config/Signal",
|
||||||
"~/Documents"
|
"~/Documents"
|
||||||
|
],
|
||||||
|
"allowRead": [
|
||||||
|
"~/Documents/Atrium"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"excludedCommands": [
|
"excludedCommands": [
|
||||||
"git push *",
|
"git push *",
|
||||||
"brew *",
|
"brew *",
|
||||||
"devbox add *",
|
"tn *",
|
||||||
"nix *"
|
"obsidian *"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"spinnerVerbs": {
|
"spinnerVerbs": {
|
||||||
@@ -118,9 +157,7 @@
|
|||||||
"autoDreamEnabled": true,
|
"autoDreamEnabled": true,
|
||||||
"theme": "light",
|
"theme": "light",
|
||||||
"editorMode": "vim",
|
"editorMode": "vim",
|
||||||
|
"remoteControlAtStartup": false,
|
||||||
"agentPushNotifEnabled": true,
|
"agentPushNotifEnabled": true,
|
||||||
"disableClaudeAiConnectors": true,
|
|
||||||
"disableWorkflows": true,
|
|
||||||
"disableArtifact": true,
|
|
||||||
"skipAutoPermissionPrompt": true
|
"skipAutoPermissionPrompt": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Mise shims so non-interactive shells (scripts, editor spawns) find tools.
|
# Mise shims so non-interactive shells (scripts, editor spawns) find tools.
|
||||||
# Interactive sessions get exact versions from `mise activate` below.
|
# Interactive sessions get exact versions from `mise activate` below.
|
||||||
fish_add_path ~/.local/share/mise/shims
|
fish_add_path --global ~/.local/bin ~/.local/share/mise/shims ~/go/bin
|
||||||
|
|
||||||
if status is-interactive
|
if status is-interactive
|
||||||
# Commands to run in interactive sessions can go here
|
# Commands to run in interactive sessions can go here
|
||||||
@@ -9,7 +9,9 @@ if status is-interactive
|
|||||||
# https://fishshell.com/docs/current/cmds/fish_greeting.html
|
# https://fishshell.com/docs/current/cmds/fish_greeting.html
|
||||||
set -g fish_greeting
|
set -g fish_greeting
|
||||||
|
|
||||||
if test -f /home/linuxbrew/.linuxbrew/bin/brew
|
if command -q brew
|
||||||
|
brew shellenv | source
|
||||||
|
else if test -x /home/linuxbrew/.linuxbrew/bin/brew
|
||||||
/home/linuxbrew/.linuxbrew/bin/brew shellenv | source
|
/home/linuxbrew/.linuxbrew/bin/brew shellenv | source
|
||||||
end
|
end
|
||||||
if command -q atuin
|
if command -q atuin
|
||||||
@@ -35,9 +37,6 @@ if status is-interactive
|
|||||||
# https://fishshell.com/docs/current/cmds/abbr.html
|
# https://fishshell.com/docs/current/cmds/abbr.html
|
||||||
abbr --add --position command pc process-compose
|
abbr --add --position command pc process-compose
|
||||||
|
|
||||||
# Set Path
|
|
||||||
fish_add_path -p /home/tgrosinger/.dotfiles/bin/linux
|
|
||||||
|
|
||||||
# Per-directory toolchains and global tools.
|
# Per-directory toolchains and global tools.
|
||||||
# https://mise.jdx.dev/getting-started.html
|
# https://mise.jdx.dev/getting-started.html
|
||||||
if type -q mise
|
if type -q mise
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# This file contains fish universal variable definitions.
|
# This file contains fish universal variable definitions.
|
||||||
# VERSION: 3.0
|
# VERSION: 3.0
|
||||||
SETUVAR __fish_initialized:4300
|
SETUVAR __fish_initialized:4300
|
||||||
SETUVAR fish_user_paths:/home/tgrosinger/\x2elocal/bin\x1e/home/tgrosinger/\x2elocal/share/mise/shims\x1e/home/tgrosinger/go/bin\x1e/home/tgrosinger/\x2edotfiles/bin/linux
|
|
||||||
|
|||||||
+4
-4
@@ -36,10 +36,10 @@
|
|||||||
sync = "!git fetch -p && git rebase origin/$(git default-branch)"
|
sync = "!git fetch -p && git rebase origin/$(git default-branch)"
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
editor = /home/linuxbrew/.linuxbrew/bin/nvim
|
editor = nvim
|
||||||
pager = delta
|
pager = delta
|
||||||
attributesfile = /home/tgrosinger/.gitattributes
|
attributesfile = ~/.gitattributes
|
||||||
excludesfile = /home/tgrosinger/.gitignore_global
|
excludesfile = ~/.gitignore_global
|
||||||
|
|
||||||
[help]
|
[help]
|
||||||
autocorrect = prompt
|
autocorrect = prompt
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
renames = true
|
renames = true
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
path = /home/tgrosinger/.config/delta/themes/catppuccin.gitconfig
|
path = ~/.config/delta/themes/catppuccin.gitconfig
|
||||||
|
|
||||||
[delta]
|
[delta]
|
||||||
# Does not behave well for comments
|
# Does not behave well for comments
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.github/instructions
|
||||||
|
.plans
|
||||||
|
.scratch
|
||||||
|
.magpie
|
||||||
|
|
||||||
|
**/.claude/settings.local.json
|
||||||
|
**/.claude/.cc-writes/
|
||||||
|
CLAUDE.local.md
|
||||||
|
|
||||||
|
.worktree-setup.sh
|
||||||
|
|
||||||
@@ -3,5 +3,5 @@
|
|||||||
podman run --rm \
|
podman run --rm \
|
||||||
-v ${HOME}/Videos/youtube:/downloads:z \
|
-v ${HOME}/Videos/youtube:/downloads:z \
|
||||||
--userns keep-id:uid=1000,gid=1000 \
|
--userns keep-id:uid=1000,gid=1000 \
|
||||||
yt-dlp:latest -S 'res:1080' $@
|
yt-dlp:latest -S 'res:1080' --extractor-args "youtube:player-client=web_embedded" $@
|
||||||
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Atuin extension for pi.
|
||||||
|
*
|
||||||
|
* Tracks bash commands executed by pi in Atuin history with author `pi`.
|
||||||
|
*
|
||||||
|
* Install with:
|
||||||
|
* atuin hook install pi
|
||||||
|
*
|
||||||
|
* Then restart pi or run /reload.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
const ATUIN_AUTHOR = "pi";
|
||||||
|
const ATUIN_TIMEOUT_MS = 10_000;
|
||||||
|
|
||||||
|
async function startHistory(
|
||||||
|
pi: ExtensionAPI,
|
||||||
|
cwd: string,
|
||||||
|
command: string,
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
try {
|
||||||
|
const result = await pi.exec(
|
||||||
|
"atuin",
|
||||||
|
["history", "start", "--author", ATUIN_AUTHOR, "--", command],
|
||||||
|
{ cwd, timeout: ATUIN_TIMEOUT_MS },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.code !== 0) return undefined;
|
||||||
|
|
||||||
|
const id = result.stdout.trim();
|
||||||
|
return id.length > 0 ? id : undefined;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function endHistory(
|
||||||
|
pi: ExtensionAPI,
|
||||||
|
cwd: string,
|
||||||
|
historyId: string,
|
||||||
|
exitCode: number,
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
await pi.exec(
|
||||||
|
"atuin",
|
||||||
|
["history", "end", historyId, "--exit", String(exitCode)],
|
||||||
|
{ cwd, timeout: ATUIN_TIMEOUT_MS },
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// Ignore Atuin failures so command execution is never blocked.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bash tool reports failures by appending a status line to the result
|
||||||
|
// text rather than exposing a numeric exit code, so recover it from there.
|
||||||
|
function exitCodeFromResult(result: unknown, isError: boolean): number {
|
||||||
|
if (!isError) return 0;
|
||||||
|
|
||||||
|
const content = (result as { content?: unknown } | undefined)?.content;
|
||||||
|
const text = Array.isArray(content)
|
||||||
|
? content
|
||||||
|
.map((part) => {
|
||||||
|
const t = (part as { text?: unknown } | undefined)?.text;
|
||||||
|
return typeof t === "string" ? t : "";
|
||||||
|
})
|
||||||
|
.join("\n")
|
||||||
|
: "";
|
||||||
|
|
||||||
|
const exited = text.match(/Command exited with code (\d+)\s*$/);
|
||||||
|
if (exited) return Number(exited[1]);
|
||||||
|
if (/Command aborted\s*$/.test(text)) return 130;
|
||||||
|
if (/Command timed out after \S+ seconds\s*$/.test(text)) return 124;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function atuinPiExtension(pi: ExtensionAPI) {
|
||||||
|
// Atuin history IDs for in-flight bash tool calls, keyed by tool call ID.
|
||||||
|
const pending = new Map<string, string>();
|
||||||
|
|
||||||
|
// Observe bash executions through events instead of registering a bash
|
||||||
|
// tool: registering one conflicts with other extensions that provide
|
||||||
|
// their own bash tool (sandboxes, RTK, remote runners), while events
|
||||||
|
// fire no matter which extension's bash tool ends up executing the
|
||||||
|
// command.
|
||||||
|
pi.on("tool_call", async (event, ctx: ExtensionContext) => {
|
||||||
|
if (event.toolName !== "bash") return;
|
||||||
|
|
||||||
|
const command = (event.input as { command?: unknown }).command;
|
||||||
|
if (typeof command !== "string" || command.length === 0) return;
|
||||||
|
|
||||||
|
const historyId = await startHistory(pi, ctx.cwd, command);
|
||||||
|
if (historyId) pending.set(event.toolCallId, historyId);
|
||||||
|
});
|
||||||
|
|
||||||
|
// tool_execution_end also fires when another extension blocks the call,
|
||||||
|
// unlike tool_result, so entries started above are always closed.
|
||||||
|
pi.on("tool_execution_end", async (event, ctx: ExtensionContext) => {
|
||||||
|
const historyId = pending.get(event.toolCallId);
|
||||||
|
if (!historyId) return;
|
||||||
|
pending.delete(event.toolCallId);
|
||||||
|
|
||||||
|
await endHistory(pi, ctx.cwd, historyId, exitCodeFromResult(event.result, event.isError));
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user