@codyswann/lisa 2.324.0 → 2.324.1
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 +71 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +102 -0
- package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +220 -0
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +562 -0
- package/all/merge/.claude/settings.json +19 -4
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +15 -6
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/standards/git-state.d.ts.map +1 -1
- package/dist/standards/git-state.js +10 -1
- package/dist/standards/git-state.js.map +1 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/rules/eager/tracked-work.md +1 -1
- package/plugins/lisa/rules/reference/tracked-work.md +1 -1
- 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/rules/eager/tracked-work.md +1 -1
- package/plugins/lisa-copilot/rules/reference/tracked-work.md +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/tracked-work-reference.mdc +1 -1
- package/plugins/lisa-cursor/rules/tracked-work.mdc +1 -1
- 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/rules/eager/tracked-work.md +1 -1
- package/plugins/src/base/rules/reference/tracked-work.md +1 -1
- package/scripts/build-plugins.sh +32 -0
- package/scripts/generate-upstream-evidence-manifest.mjs +50 -11
- package/scripts/lisa-enforcement-fallback.sh +16 -2
|
@@ -11,7 +11,7 @@ Use `lisa-track` as the single entry point:
|
|
|
11
11
|
3. Idempotently claim the resolved leaf through `lisa-tracker-claim`, which reuses the vendor build-intake claim semantics and post-read verifies the claimed-or-later state.
|
|
12
12
|
4. Before any durable repository work, persist the canonical reference with `node scripts/lisa-work-item.mjs bind <ref>` and verify the worktree-local binding.
|
|
13
13
|
|
|
14
|
-
The sequence is strict: **live validate/create -> claim -> bind -> durable work**. A
|
|
14
|
+
The sequence is strict: **live validate/create -> claim -> bind -> durable work**. A tracker answer of no, and any claim or binding failure, blocks the work. A tracker that cannot be reached — `gh` absent, or its credential refused — does not block a commit: the offline checks still run, the skip is loud on stderr, and the required `Work-Item Traceability` check re-runs the live checks with credentials before anything merges. Any other tracker failure still blocks. Tool presence or stale session text is not access.
|
|
15
15
|
|
|
16
16
|
## One canonical identity
|
|
17
17
|
|
package/scripts/build-plugins.sh
CHANGED
|
@@ -90,6 +90,38 @@ if [ -f "$SRC_DIR/base/hooks/threshold-ratchet.mjs" ]; then
|
|
|
90
90
|
done
|
|
91
91
|
fi
|
|
92
92
|
|
|
93
|
+
# Enforcement guards for host projects.
|
|
94
|
+
#
|
|
95
|
+
# These three are declared in the Lisa plugin, so a container whose plugin
|
|
96
|
+
# install fails runs with no PreToolUse enforcement at all — silently. Lisa
|
|
97
|
+
# closes that with a repository hook, which reaches a cloud session because it
|
|
98
|
+
# is part of the clone; a host project needs the same thing, and has no
|
|
99
|
+
# plugins/ directory to fall back on.
|
|
100
|
+
#
|
|
101
|
+
# Synced rather than hand-copied, for the same reason the ratchet above is: a
|
|
102
|
+
# unit test asserts byte-equality, so the shipped guard can never drift from the
|
|
103
|
+
# reviewed one.
|
|
104
|
+
HOST_GUARD_DIR="$ROOT_DIR/all/copy-overwrite/scripts/lisa-hooks"
|
|
105
|
+
if [ -d "$SRC_DIR/base/hooks" ]; then
|
|
106
|
+
mkdir -p "$HOST_GUARD_DIR"
|
|
107
|
+
fi
|
|
108
|
+
for guard in block-no-verify parity-safety-net block-shell-json-parsing; do
|
|
109
|
+
if [ -f "$SRC_DIR/base/hooks/$guard.sh" ]; then
|
|
110
|
+
cp "$SRC_DIR/base/hooks/$guard.sh" "$HOST_GUARD_DIR/$guard.sh"
|
|
111
|
+
chmod +x "$HOST_GUARD_DIR/$guard.sh"
|
|
112
|
+
fi
|
|
113
|
+
done
|
|
114
|
+
# The dispatcher itself, so a host project gets the identical entry point.
|
|
115
|
+
# Guarded like the ratchet above: this script is also run against isolated
|
|
116
|
+
# fixtures that carry a source tree but none of the repository's own scripts,
|
|
117
|
+
# and an unconditional copy fails the whole build there.
|
|
118
|
+
if [ -f "$ROOT_DIR/scripts/lisa-enforcement-fallback.sh" ]; then
|
|
119
|
+
mkdir -p "$ROOT_DIR/all/copy-overwrite/scripts"
|
|
120
|
+
cp "$ROOT_DIR/scripts/lisa-enforcement-fallback.sh" \
|
|
121
|
+
"$ROOT_DIR/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh"
|
|
122
|
+
chmod +x "$ROOT_DIR/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh"
|
|
123
|
+
fi
|
|
124
|
+
|
|
93
125
|
# Stack-specific plugins (NO base copy)
|
|
94
126
|
STACKS=(typescript expo nestjs cdk harper-fabric phaser rails)
|
|
95
127
|
for stack in "${STACKS[@]}"; do
|
|
@@ -42,18 +42,57 @@ const forbiddenBasenames = new Set([
|
|
|
42
42
|
".mcp.json",
|
|
43
43
|
"audit.local",
|
|
44
44
|
]);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"https://github.com/CodySwannGT/lisa",
|
|
48
|
-
"git@github.com:CodySwannGT/lisa.git",
|
|
49
|
-
]);
|
|
45
|
+
/** The repository this manifest may be generated from. Not a URL — see below. */
|
|
46
|
+
const canonicalRepository = "CodySwannGT/lisa";
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The `owner/repo` an origin URL points at, or null if it names none.
|
|
50
|
+
*
|
|
51
|
+
* The guard exists to refuse hash-pinning from a fork, which is a question
|
|
52
|
+
* about **identity**. It used to compare the whole origin URL against a list of
|
|
53
|
+
* spellings, which answers a question about **transport** instead — and the two
|
|
54
|
+
* come apart in ordinary situations, not just exotic ones. `remote.origin.url`
|
|
55
|
+
* and `remote.origin.pushurl` can differ, `url.<base>.insteadOf` rewrites what
|
|
56
|
+
* `git remote get-url` returns, and a cloud container clones through a local
|
|
57
|
+
* git proxy. All three are proxied checkouts of the real repository, and all
|
|
58
|
+
* three were refused before a single hash was checked.
|
|
59
|
+
*
|
|
60
|
+
* Comparing the path keeps the property that matters: a fork is
|
|
61
|
+
* `someone-else/lisa` and is still refused, while `https://…`, `git@…` and
|
|
62
|
+
* `http://local_proxy@127.0.0.1:PORT/git/…` all resolve to the same identity.
|
|
63
|
+
* @param {string} url Whatever `git remote get-url` returned.
|
|
64
|
+
* @returns {string|null} `owner/repo`, lowercased, or null.
|
|
65
|
+
*/
|
|
66
|
+
function repositoryPath(url) {
|
|
67
|
+
// scp-style (git@host:owner/repo.git) is not a URL, so it is handled first.
|
|
68
|
+
const scp = /^[^/]+@[^:/]+:(?<path>.+)$/u.exec(url);
|
|
69
|
+
const raw =
|
|
70
|
+
scp?.groups?.path ?? (URL.canParse(url) ? new URL(url).pathname : null);
|
|
71
|
+
if (raw === null) return null;
|
|
72
|
+
const segments = raw
|
|
73
|
+
.replace(/\.git$/u, "")
|
|
74
|
+
.split("/")
|
|
75
|
+
.filter(Boolean);
|
|
76
|
+
if (segments.length < 2) return null;
|
|
77
|
+
return segments.slice(-2).join("/").toLowerCase();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The configured value rather than the resolved one, for the same reason the
|
|
81
|
+
// comparison is by path: `url.<base>.insteadOf` rewrites what `git remote
|
|
82
|
+
// get-url` returns, so it answers "how do I reach this" rather than "what is
|
|
83
|
+
// this". Falls back to the resolved URL only if no value is configured.
|
|
84
|
+
const originUrl = execFileSync(
|
|
85
|
+
"git",
|
|
86
|
+
["config", "--get", "remote.origin.url"],
|
|
87
|
+
{ cwd: repoRoot, encoding: "utf8" }
|
|
88
|
+
).trim();
|
|
89
|
+
if (repositoryPath(originUrl) !== canonicalRepository.toLowerCase()) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Refusing to generate from a non-canonical repository.\n` +
|
|
92
|
+
`origin resolves to: ${repositoryPath(originUrl) ?? "(no owner/repo)"}\n` +
|
|
93
|
+
`expected: ${canonicalRepository}\n` +
|
|
94
|
+
`(origin URL was: ${originUrl})`
|
|
95
|
+
);
|
|
57
96
|
}
|
|
58
97
|
|
|
59
98
|
const tracked = execFileSync("git", ["ls-files", "-z"], {
|
|
@@ -34,10 +34,24 @@ if [ -f "$installed" ] && grep -q '"lisa@lisa"' "$installed" 2>/dev/null; then
|
|
|
34
34
|
exit 0
|
|
35
35
|
fi
|
|
36
36
|
|
|
37
|
+
# Where the guards live depends on which repository this is.
|
|
38
|
+
#
|
|
39
|
+
# `plugins/lisa/hooks/` exists only in the Lisa monorepo. A host project gets
|
|
40
|
+
# the same three scripts written into its checkout by `lisa apply`, because a
|
|
41
|
+
# host project whose plugin install fails has exactly the same hole and no
|
|
42
|
+
# `plugins/` directory to fall back on.
|
|
37
43
|
status=0
|
|
38
44
|
for guard in block-no-verify parity-safety-net block-shell-json-parsing; do
|
|
39
|
-
script="
|
|
40
|
-
|
|
45
|
+
script=""
|
|
46
|
+
for candidate in \
|
|
47
|
+
"$repo_root/scripts/lisa-hooks/$guard.sh" \
|
|
48
|
+
"$repo_root/plugins/lisa/hooks/$guard.sh"; do
|
|
49
|
+
if [ -f "$candidate" ]; then
|
|
50
|
+
script="$candidate"
|
|
51
|
+
break
|
|
52
|
+
fi
|
|
53
|
+
done
|
|
54
|
+
[ -n "$script" ] || continue
|
|
41
55
|
# Each guard reads the tool payload on stdin and signals a refusal with exit
|
|
42
56
|
# 2. The payload is replayed to every one of them, and the strongest refusal
|
|
43
57
|
# is returned — a guard that declines must not be able to clear one that did
|