@codyswann/lisa 4.45.1 → 4.45.3
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/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +49 -0
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +115 -12
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +6 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +11 -6
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +115 -12
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/parity-safety-net.sh +115 -12
- package/scripts/check-typecheck-tests.mjs +229 -72
- package/scripts/lib/dependency-tree.mjs +136 -0
- package/scripts/lisa-enforcement-fallback.sh +49 -0
- package/typescript/copy-contents/.husky/pre-push +45 -0
|
@@ -405,7 +405,12 @@ readonly FOLLOW_MAX_TOTAL_BYTES=524288
|
|
|
405
405
|
readonly FOLLOW_MAX_FILES=8
|
|
406
406
|
readonly FOLLOW_MAX_DEPTH=3
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
# Effective working directory established by a literal `cd` in the command, and
|
|
409
|
+
# the flag that says a `cd` happened whose target could NOT be read literally.
|
|
410
|
+
# Empty + 0 means no `cd` has been seen and the session's own cwd governs.
|
|
411
|
+
follow_cwd=""
|
|
412
|
+
follow_cwd_unknown=0
|
|
413
|
+
follow_normalized=""
|
|
409
414
|
follow_paths=$'\n'
|
|
410
415
|
follow_names=""
|
|
411
416
|
follow_count=0
|
|
@@ -420,6 +425,10 @@ see is the thing it exists to stop.
|
|
|
420
425
|
|
|
421
426
|
- Name the script by a LITERAL path that exists and is readable — \`bash
|
|
422
427
|
./scripts/x.sh\` rather than \`bash \"\$SCRIPT\"\` — and the guard can classify it.
|
|
428
|
+
- A leading \`cd\` the guard cannot read literally — \`cd \"\$DIR\" && bash x.sh\` —
|
|
429
|
+
leaves it unable to say WHICH copy of \`x.sh\` would run, and a same-named file
|
|
430
|
+
in another directory is a different file. Spell the directory out, or give the
|
|
431
|
+
script its full path.
|
|
423
432
|
- A file past the inspection cap is refused rather than half-scanned, because a
|
|
424
433
|
truncated scan reports a confident ALLOW about text it never read. Split it,
|
|
425
434
|
or run it manually outside the agent.
|
|
@@ -550,15 +559,77 @@ follow_split() {
|
|
|
550
559
|
'
|
|
551
560
|
}
|
|
552
561
|
|
|
553
|
-
#
|
|
554
|
-
#
|
|
555
|
-
|
|
556
|
-
|
|
562
|
+
# Collapse `.`, `..` and empty segments so the path a verdict NAMES is the one a
|
|
563
|
+
# reader recognises. Purely lexical, and it cannot move a verdict: every
|
|
564
|
+
# component has already been proven to exist by the `-d` test that follows, and
|
|
565
|
+
# the `-f`/`-r` tests are applied to the collapsed path either way.
|
|
566
|
+
follow_normalize() {
|
|
567
|
+
local p="$1" out="" seg
|
|
568
|
+
local IFS=/
|
|
569
|
+
set -f
|
|
570
|
+
# The word split is the point: `$p` is being addressed one path segment at a
|
|
571
|
+
# time, and the glob guard above keeps a literal `*` from expanding.
|
|
572
|
+
# shellcheck disable=SC2086
|
|
573
|
+
for seg in $p; do
|
|
574
|
+
case "$seg" in
|
|
575
|
+
"" | .) ;;
|
|
576
|
+
..) out="${out%/*}" ;;
|
|
577
|
+
*) out="$out/$seg" ;;
|
|
578
|
+
esac
|
|
579
|
+
done
|
|
580
|
+
set +f
|
|
581
|
+
follow_normalized="${out:-/}"
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
# Track the working directory a literal `cd` establishes, so a relative executed
|
|
585
|
+
# path resolves against the directory the command will actually have.
|
|
586
|
+
#
|
|
587
|
+
# This REPLACES the session's own cwd rather than adding to it. It used to be an
|
|
588
|
+
# extra base appended AFTER `$PWD`, so `$PWD` always won and
|
|
589
|
+
# `cd <other-checkout> && bash scripts/x.sh` was classified against the session
|
|
590
|
+
# checkout's same-named copy. That is not a resolution failure — it succeeds,
|
|
591
|
+
# against a real and readable file, and the verdict is reported with full
|
|
592
|
+
# confidence about text nobody was about to run (CodySwannGT/lisa#3933). Two
|
|
593
|
+
# checkouts of one repository differ by exactly the work in flight, which is the
|
|
594
|
+
# entire point of the second one, so the copy that would RUN is the only copy
|
|
595
|
+
# whose verdict means anything. Wrong in both directions, and the expensive
|
|
596
|
+
# direction is silent: the dangerous line sits in the copy that would run and
|
|
597
|
+
# the guard reads the pristine one.
|
|
598
|
+
#
|
|
599
|
+
# A target this hook cannot turn into a literal directory marks the cwd UNKNOWN
|
|
600
|
+
# instead of leaving a stale one in place. `follow_locate` then refuses a
|
|
601
|
+
# relative token rather than guessing, which is the honest-refusal doctrine the
|
|
602
|
+
# rest of this block already follows: a confident scan of the wrong file is
|
|
603
|
+
# strictly worse than saying it could not tell.
|
|
604
|
+
follow_cd() {
|
|
605
|
+
local d="$1" home="${HOME:-}"
|
|
606
|
+
# The tilde arms are LITERAL text — the unexpanded spelling the hook was
|
|
607
|
+
# handed — for the reason follow_locate's arms document.
|
|
608
|
+
# shellcheck disable=SC2088
|
|
609
|
+
case "$d" in
|
|
610
|
+
'~') d="$home" ;;
|
|
611
|
+
'~/'*) d="$home/${d#'~/'}" ;;
|
|
612
|
+
esac
|
|
613
|
+
case "$d" in
|
|
614
|
+
"" | -* | *'$'* | *'*'* | *'?'* | *'`'* | *'{'* | *'['*)
|
|
615
|
+
follow_cwd=""
|
|
616
|
+
follow_cwd_unknown=1
|
|
617
|
+
return 0
|
|
618
|
+
;;
|
|
619
|
+
esac
|
|
557
620
|
case "$d" in
|
|
558
|
-
|
|
621
|
+
/*) ;;
|
|
622
|
+
*) d="${follow_cwd:-$PWD}/$d" ;;
|
|
559
623
|
esac
|
|
560
|
-
|
|
561
|
-
|
|
624
|
+
follow_normalize "$d"
|
|
625
|
+
d="$follow_normalized"
|
|
626
|
+
if [ -d "$d" ]; then
|
|
627
|
+
follow_cwd="$d"
|
|
628
|
+
follow_cwd_unknown=0
|
|
629
|
+
else
|
|
630
|
+
follow_cwd=""
|
|
631
|
+
follow_cwd_unknown=1
|
|
632
|
+
fi
|
|
562
633
|
}
|
|
563
634
|
|
|
564
635
|
# Resolve one executed-file operand to a readable regular file, or fail.
|
|
@@ -571,6 +642,7 @@ follow_add_base() {
|
|
|
571
642
|
# this hook cannot evaluate.
|
|
572
643
|
follow_locate() {
|
|
573
644
|
local token="$1" home="${HOME:-}" tmp="${TMPDIR:-/tmp}" proj="${CLAUDE_PROJECT_DIR:-$PWD}" base
|
|
645
|
+
local cwd="${follow_cwd:-$PWD}"
|
|
574
646
|
follow_located=""
|
|
575
647
|
tmp="${tmp%/}"
|
|
576
648
|
[ -n "$tmp" ] || tmp="/tmp"
|
|
@@ -584,8 +656,14 @@ follow_locate() {
|
|
|
584
656
|
'${TMPDIR}' | '${TMPDIR}'/*) token="$tmp${token#'${TMPDIR}'}" ;;
|
|
585
657
|
'$HOME' | '$HOME'/*) token="$home${token#'$HOME'}" ;;
|
|
586
658
|
'${HOME}' | '${HOME}'/*) token="$home${token#'${HOME}'}" ;;
|
|
587
|
-
'$PWD' | '$PWD'/*)
|
|
588
|
-
|
|
659
|
+
'$PWD' | '$PWD'/*)
|
|
660
|
+
[ "$follow_cwd_unknown" -eq 0 ] || return 1
|
|
661
|
+
token="$cwd${token#'$PWD'}"
|
|
662
|
+
;;
|
|
663
|
+
'${PWD}' | '${PWD}'/*)
|
|
664
|
+
[ "$follow_cwd_unknown" -eq 0 ] || return 1
|
|
665
|
+
token="$cwd${token#'${PWD}'}"
|
|
666
|
+
;;
|
|
589
667
|
'$CLAUDE_PROJECT_DIR' | '$CLAUDE_PROJECT_DIR'/*) token="$proj${token#'$CLAUDE_PROJECT_DIR'}" ;;
|
|
590
668
|
'${CLAUDE_PROJECT_DIR}' | '${CLAUDE_PROJECT_DIR}'/*) token="$proj${token#'${CLAUDE_PROJECT_DIR}'}" ;;
|
|
591
669
|
esac
|
|
@@ -597,13 +675,26 @@ follow_locate() {
|
|
|
597
675
|
return 0
|
|
598
676
|
;;
|
|
599
677
|
esac
|
|
678
|
+
# Past this point the token is RELATIVE, so which directory it is resolved
|
|
679
|
+
# from decides which file the verdict is about.
|
|
680
|
+
if [ "$follow_cwd_unknown" -eq 1 ]; then
|
|
681
|
+
return 1
|
|
682
|
+
fi
|
|
683
|
+
if [ -n "$follow_cwd" ]; then
|
|
684
|
+
# A literal `cd` names the directory the shell will be in. It is the only
|
|
685
|
+
# candidate — falling back to `$PWD` here is what made the guard report
|
|
686
|
+
# confidently about a same-named file in another checkout.
|
|
687
|
+
[ -f "$follow_cwd/$token" ] && [ -r "$follow_cwd/$token" ] || return 1
|
|
688
|
+
follow_located="$follow_cwd/$token"
|
|
689
|
+
return 0
|
|
690
|
+
fi
|
|
600
691
|
while IFS= read -r base; do
|
|
601
692
|
[ -n "$base" ] || continue
|
|
602
693
|
if [ -f "$base/$token" ] && [ -r "$base/$token" ]; then
|
|
603
694
|
follow_located="$base/$token"
|
|
604
695
|
return 0
|
|
605
696
|
fi
|
|
606
|
-
done <<<"$PWD"$'\n'"$proj
|
|
697
|
+
done <<<"$PWD"$'\n'"$proj"
|
|
607
698
|
return 1
|
|
608
699
|
}
|
|
609
700
|
|
|
@@ -636,7 +727,15 @@ follow_take() {
|
|
|
636
727
|
follow_names="$follow_names $path"
|
|
637
728
|
followed_text="$followed_text"$'\n'"$content"
|
|
638
729
|
if [ "$depth" -lt "$FOLLOW_MAX_DEPTH" ]; then
|
|
730
|
+
# A `cd` inside the followed script governs what THAT script goes on to
|
|
731
|
+
# execute, and nothing after it in the command that ran the script — the
|
|
732
|
+
# child inherits this directory but cannot change the parent's. Saving and
|
|
733
|
+
# restoring is what keeps a nested `cd` from silently re-pointing the rest
|
|
734
|
+
# of the outer walk.
|
|
735
|
+
local saved_cwd="$follow_cwd" saved_unknown="$follow_cwd_unknown"
|
|
639
736
|
follow_scan "$content" "$((depth + 1))"
|
|
737
|
+
follow_cwd="$saved_cwd"
|
|
738
|
+
follow_cwd_unknown="$saved_unknown"
|
|
640
739
|
fi
|
|
641
740
|
}
|
|
642
741
|
|
|
@@ -861,7 +960,11 @@ follow_scan() {
|
|
|
861
960
|
cd)
|
|
862
961
|
if [ $((i + 1)) -lt "$n" ]; then
|
|
863
962
|
follow_unwrap "${toks[i + 1]}"
|
|
864
|
-
|
|
963
|
+
follow_cd "$follow_unwrapped"
|
|
964
|
+
else
|
|
965
|
+
# A bare `cd` is `cd "$HOME"`, and leaving the previous directory in
|
|
966
|
+
# place would resolve later tokens from a directory the shell left.
|
|
967
|
+
follow_cd "${HOME:-}"
|
|
865
968
|
fi
|
|
866
969
|
cmd_pos=0
|
|
867
970
|
i=$((i + 1))
|
|
@@ -405,7 +405,12 @@ readonly FOLLOW_MAX_TOTAL_BYTES=524288
|
|
|
405
405
|
readonly FOLLOW_MAX_FILES=8
|
|
406
406
|
readonly FOLLOW_MAX_DEPTH=3
|
|
407
407
|
|
|
408
|
-
|
|
408
|
+
# Effective working directory established by a literal `cd` in the command, and
|
|
409
|
+
# the flag that says a `cd` happened whose target could NOT be read literally.
|
|
410
|
+
# Empty + 0 means no `cd` has been seen and the session's own cwd governs.
|
|
411
|
+
follow_cwd=""
|
|
412
|
+
follow_cwd_unknown=0
|
|
413
|
+
follow_normalized=""
|
|
409
414
|
follow_paths=$'\n'
|
|
410
415
|
follow_names=""
|
|
411
416
|
follow_count=0
|
|
@@ -420,6 +425,10 @@ see is the thing it exists to stop.
|
|
|
420
425
|
|
|
421
426
|
- Name the script by a LITERAL path that exists and is readable — \`bash
|
|
422
427
|
./scripts/x.sh\` rather than \`bash \"\$SCRIPT\"\` — and the guard can classify it.
|
|
428
|
+
- A leading \`cd\` the guard cannot read literally — \`cd \"\$DIR\" && bash x.sh\` —
|
|
429
|
+
leaves it unable to say WHICH copy of \`x.sh\` would run, and a same-named file
|
|
430
|
+
in another directory is a different file. Spell the directory out, or give the
|
|
431
|
+
script its full path.
|
|
423
432
|
- A file past the inspection cap is refused rather than half-scanned, because a
|
|
424
433
|
truncated scan reports a confident ALLOW about text it never read. Split it,
|
|
425
434
|
or run it manually outside the agent.
|
|
@@ -550,15 +559,77 @@ follow_split() {
|
|
|
550
559
|
'
|
|
551
560
|
}
|
|
552
561
|
|
|
553
|
-
#
|
|
554
|
-
#
|
|
555
|
-
|
|
556
|
-
|
|
562
|
+
# Collapse `.`, `..` and empty segments so the path a verdict NAMES is the one a
|
|
563
|
+
# reader recognises. Purely lexical, and it cannot move a verdict: every
|
|
564
|
+
# component has already been proven to exist by the `-d` test that follows, and
|
|
565
|
+
# the `-f`/`-r` tests are applied to the collapsed path either way.
|
|
566
|
+
follow_normalize() {
|
|
567
|
+
local p="$1" out="" seg
|
|
568
|
+
local IFS=/
|
|
569
|
+
set -f
|
|
570
|
+
# The word split is the point: `$p` is being addressed one path segment at a
|
|
571
|
+
# time, and the glob guard above keeps a literal `*` from expanding.
|
|
572
|
+
# shellcheck disable=SC2086
|
|
573
|
+
for seg in $p; do
|
|
574
|
+
case "$seg" in
|
|
575
|
+
"" | .) ;;
|
|
576
|
+
..) out="${out%/*}" ;;
|
|
577
|
+
*) out="$out/$seg" ;;
|
|
578
|
+
esac
|
|
579
|
+
done
|
|
580
|
+
set +f
|
|
581
|
+
follow_normalized="${out:-/}"
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
# Track the working directory a literal `cd` establishes, so a relative executed
|
|
585
|
+
# path resolves against the directory the command will actually have.
|
|
586
|
+
#
|
|
587
|
+
# This REPLACES the session's own cwd rather than adding to it. It used to be an
|
|
588
|
+
# extra base appended AFTER `$PWD`, so `$PWD` always won and
|
|
589
|
+
# `cd <other-checkout> && bash scripts/x.sh` was classified against the session
|
|
590
|
+
# checkout's same-named copy. That is not a resolution failure — it succeeds,
|
|
591
|
+
# against a real and readable file, and the verdict is reported with full
|
|
592
|
+
# confidence about text nobody was about to run (CodySwannGT/lisa#3933). Two
|
|
593
|
+
# checkouts of one repository differ by exactly the work in flight, which is the
|
|
594
|
+
# entire point of the second one, so the copy that would RUN is the only copy
|
|
595
|
+
# whose verdict means anything. Wrong in both directions, and the expensive
|
|
596
|
+
# direction is silent: the dangerous line sits in the copy that would run and
|
|
597
|
+
# the guard reads the pristine one.
|
|
598
|
+
#
|
|
599
|
+
# A target this hook cannot turn into a literal directory marks the cwd UNKNOWN
|
|
600
|
+
# instead of leaving a stale one in place. `follow_locate` then refuses a
|
|
601
|
+
# relative token rather than guessing, which is the honest-refusal doctrine the
|
|
602
|
+
# rest of this block already follows: a confident scan of the wrong file is
|
|
603
|
+
# strictly worse than saying it could not tell.
|
|
604
|
+
follow_cd() {
|
|
605
|
+
local d="$1" home="${HOME:-}"
|
|
606
|
+
# The tilde arms are LITERAL text — the unexpanded spelling the hook was
|
|
607
|
+
# handed — for the reason follow_locate's arms document.
|
|
608
|
+
# shellcheck disable=SC2088
|
|
609
|
+
case "$d" in
|
|
610
|
+
'~') d="$home" ;;
|
|
611
|
+
'~/'*) d="$home/${d#'~/'}" ;;
|
|
612
|
+
esac
|
|
613
|
+
case "$d" in
|
|
614
|
+
"" | -* | *'$'* | *'*'* | *'?'* | *'`'* | *'{'* | *'['*)
|
|
615
|
+
follow_cwd=""
|
|
616
|
+
follow_cwd_unknown=1
|
|
617
|
+
return 0
|
|
618
|
+
;;
|
|
619
|
+
esac
|
|
557
620
|
case "$d" in
|
|
558
|
-
|
|
621
|
+
/*) ;;
|
|
622
|
+
*) d="${follow_cwd:-$PWD}/$d" ;;
|
|
559
623
|
esac
|
|
560
|
-
|
|
561
|
-
|
|
624
|
+
follow_normalize "$d"
|
|
625
|
+
d="$follow_normalized"
|
|
626
|
+
if [ -d "$d" ]; then
|
|
627
|
+
follow_cwd="$d"
|
|
628
|
+
follow_cwd_unknown=0
|
|
629
|
+
else
|
|
630
|
+
follow_cwd=""
|
|
631
|
+
follow_cwd_unknown=1
|
|
632
|
+
fi
|
|
562
633
|
}
|
|
563
634
|
|
|
564
635
|
# Resolve one executed-file operand to a readable regular file, or fail.
|
|
@@ -571,6 +642,7 @@ follow_add_base() {
|
|
|
571
642
|
# this hook cannot evaluate.
|
|
572
643
|
follow_locate() {
|
|
573
644
|
local token="$1" home="${HOME:-}" tmp="${TMPDIR:-/tmp}" proj="${CLAUDE_PROJECT_DIR:-$PWD}" base
|
|
645
|
+
local cwd="${follow_cwd:-$PWD}"
|
|
574
646
|
follow_located=""
|
|
575
647
|
tmp="${tmp%/}"
|
|
576
648
|
[ -n "$tmp" ] || tmp="/tmp"
|
|
@@ -584,8 +656,14 @@ follow_locate() {
|
|
|
584
656
|
'${TMPDIR}' | '${TMPDIR}'/*) token="$tmp${token#'${TMPDIR}'}" ;;
|
|
585
657
|
'$HOME' | '$HOME'/*) token="$home${token#'$HOME'}" ;;
|
|
586
658
|
'${HOME}' | '${HOME}'/*) token="$home${token#'${HOME}'}" ;;
|
|
587
|
-
'$PWD' | '$PWD'/*)
|
|
588
|
-
|
|
659
|
+
'$PWD' | '$PWD'/*)
|
|
660
|
+
[ "$follow_cwd_unknown" -eq 0 ] || return 1
|
|
661
|
+
token="$cwd${token#'$PWD'}"
|
|
662
|
+
;;
|
|
663
|
+
'${PWD}' | '${PWD}'/*)
|
|
664
|
+
[ "$follow_cwd_unknown" -eq 0 ] || return 1
|
|
665
|
+
token="$cwd${token#'${PWD}'}"
|
|
666
|
+
;;
|
|
589
667
|
'$CLAUDE_PROJECT_DIR' | '$CLAUDE_PROJECT_DIR'/*) token="$proj${token#'$CLAUDE_PROJECT_DIR'}" ;;
|
|
590
668
|
'${CLAUDE_PROJECT_DIR}' | '${CLAUDE_PROJECT_DIR}'/*) token="$proj${token#'${CLAUDE_PROJECT_DIR}'}" ;;
|
|
591
669
|
esac
|
|
@@ -597,13 +675,26 @@ follow_locate() {
|
|
|
597
675
|
return 0
|
|
598
676
|
;;
|
|
599
677
|
esac
|
|
678
|
+
# Past this point the token is RELATIVE, so which directory it is resolved
|
|
679
|
+
# from decides which file the verdict is about.
|
|
680
|
+
if [ "$follow_cwd_unknown" -eq 1 ]; then
|
|
681
|
+
return 1
|
|
682
|
+
fi
|
|
683
|
+
if [ -n "$follow_cwd" ]; then
|
|
684
|
+
# A literal `cd` names the directory the shell will be in. It is the only
|
|
685
|
+
# candidate — falling back to `$PWD` here is what made the guard report
|
|
686
|
+
# confidently about a same-named file in another checkout.
|
|
687
|
+
[ -f "$follow_cwd/$token" ] && [ -r "$follow_cwd/$token" ] || return 1
|
|
688
|
+
follow_located="$follow_cwd/$token"
|
|
689
|
+
return 0
|
|
690
|
+
fi
|
|
600
691
|
while IFS= read -r base; do
|
|
601
692
|
[ -n "$base" ] || continue
|
|
602
693
|
if [ -f "$base/$token" ] && [ -r "$base/$token" ]; then
|
|
603
694
|
follow_located="$base/$token"
|
|
604
695
|
return 0
|
|
605
696
|
fi
|
|
606
|
-
done <<<"$PWD"$'\n'"$proj
|
|
697
|
+
done <<<"$PWD"$'\n'"$proj"
|
|
607
698
|
return 1
|
|
608
699
|
}
|
|
609
700
|
|
|
@@ -636,7 +727,15 @@ follow_take() {
|
|
|
636
727
|
follow_names="$follow_names $path"
|
|
637
728
|
followed_text="$followed_text"$'\n'"$content"
|
|
638
729
|
if [ "$depth" -lt "$FOLLOW_MAX_DEPTH" ]; then
|
|
730
|
+
# A `cd` inside the followed script governs what THAT script goes on to
|
|
731
|
+
# execute, and nothing after it in the command that ran the script — the
|
|
732
|
+
# child inherits this directory but cannot change the parent's. Saving and
|
|
733
|
+
# restoring is what keeps a nested `cd` from silently re-pointing the rest
|
|
734
|
+
# of the outer walk.
|
|
735
|
+
local saved_cwd="$follow_cwd" saved_unknown="$follow_cwd_unknown"
|
|
639
736
|
follow_scan "$content" "$((depth + 1))"
|
|
737
|
+
follow_cwd="$saved_cwd"
|
|
738
|
+
follow_cwd_unknown="$saved_unknown"
|
|
640
739
|
fi
|
|
641
740
|
}
|
|
642
741
|
|
|
@@ -861,7 +960,11 @@ follow_scan() {
|
|
|
861
960
|
cd)
|
|
862
961
|
if [ $((i + 1)) -lt "$n" ]; then
|
|
863
962
|
follow_unwrap "${toks[i + 1]}"
|
|
864
|
-
|
|
963
|
+
follow_cd "$follow_unwrapped"
|
|
964
|
+
else
|
|
965
|
+
# A bare `cd` is `cd "$HOME"`, and leaving the previous directory in
|
|
966
|
+
# place would resolve later tokens from a directory the shell left.
|
|
967
|
+
follow_cd "${HOME:-}"
|
|
865
968
|
fi
|
|
866
969
|
cmd_pos=0
|
|
867
970
|
i=$((i + 1))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.45.
|
|
3
|
+
"version": "4.45.3",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.45.
|
|
3
|
+
"version": "4.45.3",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.45.
|
|
3
|
+
"version": "4.45.3",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.45.
|
|
3
|
+
"version": "4.45.3",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "4.45.
|
|
3
|
+
"version": "4.45.3",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|