@erclx/aitk 3.28.0 → 3.29.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "3.28.0",
4
+ "version": "3.29.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -13,7 +13,7 @@ description: Report file paths correctly for the reading surface and group them
13
13
  - Both forms govern a path emitted in a response. A path written into a markdown file follows the markdown standard instead, which your toolkit resolves by name, and which backticks a file reference and never repeats it as a link label.
14
14
  - Use the path the user's editor can resolve. The editor is rooted at the main project root.
15
15
  - In the main worktree: relative from `pwd` works because `pwd` equals the editor root.
16
- - In a linked worktree (under `.claude/worktrees/<name>/`): use absolute paths. Relative paths from worktree `pwd` would not resolve against the editor's project root.
16
+ - In a linked worktree (under `.claude/worktrees/<name>/`): use absolute paths. Relative paths from worktree `pwd` would not resolve against the editor's project root. A `PostToolUse` hook computes this form after each write and hands it back as additional context where it is installed. Prefer that form when it arrives, and fall back to computing the absolute path yourself when it does not.
17
17
 
18
18
  ## Grouping multiple files
19
19
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "3.28.0",
4
+ "version": "3.29.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Hands back the absolute path form for a write made from a linked worktree.
4
+ #
5
+ # A relative path emitted from a linked worktree resolves against that
6
+ # worktree rather than the editor root, so the terminal's path detection and
7
+ # the desktop app's link both fail silently: nothing happens on the click
8
+ # and no error appears. This computes the fact a session was asking itself
9
+ # to infer on every response and hands the answer back instead.
10
+ #
11
+ # The entrypoint branch (bare vs. `file://` link) stays prose in
12
+ # governance/rules/core/015-output.md. CLAUDE_CODE_ENTRYPOINT is not among
13
+ # the environment variables Claude Code documents as passed to a hook
14
+ # subprocess, unlike CLAUDE_PROJECT_DIR, so a hook cannot read it reliably.
15
+ #
16
+ # The worktree branch comes from the path rather than from `git rev-parse`,
17
+ # the way `tasks-index.sh` and `memory-index.sh` already derive their main
18
+ # root from a path suffix instead of the session. A git call would answer for
19
+ # whatever directory the hook's own process happens to run in, which is not
20
+ # necessarily the worktree the write came from.
21
+
22
+ # Claude Code sends a payload and closes stdin. A bare read with nothing
23
+ # feeding it blocks forever and holds the session open, so the read is
24
+ # bounded. `read` rather than `timeout cat`, which macOS does not ship.
25
+ IFS= read -r -d '' -t 2 input
26
+ [ -n "$input" ] || {
27
+ printf '%s reads a Claude Code hook payload on stdin and cannot be run by hand.\n' "${0##*/}" >&2
28
+ exit 1
29
+ }
30
+
31
+ tool=$(printf '%s' "$input" | jq -r '.tool_name // empty')
32
+ case "$tool" in
33
+ Write | Edit | MultiEdit) ;;
34
+ *) exit 0 ;;
35
+ esac
36
+
37
+ file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
38
+ [ -n "$file_path" ] || exit 0
39
+
40
+ # A path with no worktree segment is either the main worktree, where a
41
+ # relative path already resolves against the editor root, or a path this
42
+ # hook cannot place. Either way there is nothing to hand back.
43
+ case "$file_path" in
44
+ */.claude/worktrees/*) ;;
45
+ *) exit 0 ;;
46
+ esac
47
+
48
+ abs_path=$(realpath -- "$file_path" 2>/dev/null)
49
+ if [ -z "$abs_path" ]; then
50
+ jq -nc --arg msg "path-form.sh could not resolve an absolute form for $file_path from this linked worktree. Report the path per the worktree branch in the output rule instead of guessing." \
51
+ '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:$msg}}'
52
+ exit 0
53
+ fi
54
+
55
+ jq -nc --arg path "$abs_path" \
56
+ '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:("This write is from a linked worktree. When reporting this path in your response, use its absolute form: " + $path)}}'
57
+ exit 0
@@ -35,6 +35,10 @@
35
35
  {
36
36
  "type": "command",
37
37
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/memory-index.sh"
38
+ },
39
+ {
40
+ "type": "command",
41
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/path-form.sh"
38
42
  }
39
43
  ]
40
44
  }