@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.
Files changed (73) hide show
  1. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +71 -0
  2. package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +102 -0
  3. package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +220 -0
  4. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +562 -0
  5. package/all/merge/.claude/settings.json +19 -4
  6. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.js +15 -6
  8. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  9. package/dist/standards/git-state.d.ts.map +1 -1
  10. package/dist/standards/git-state.js +10 -1
  11. package/dist/standards/git-state.js.map +1 -1
  12. package/package.json +1 -1
  13. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa/rules/eager/tracked-work.md +1 -1
  16. package/plugins/lisa/rules/reference/tracked-work.md +1 -1
  17. package/plugins/lisa-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  21. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-copilot/rules/eager/tracked-work.md +1 -1
  25. package/plugins/lisa-copilot/rules/reference/tracked-work.md +1 -1
  26. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-cursor/rules/tracked-work-reference.mdc +1 -1
  28. package/plugins/lisa-cursor/rules/tracked-work.mdc +1 -1
  29. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-agy/plugin.json +1 -1
  32. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  52. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-agy/plugin.json +1 -1
  57. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  62. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  67. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/src/base/rules/eager/tracked-work.md +1 -1
  70. package/plugins/src/base/rules/reference/tracked-work.md +1 -1
  71. package/scripts/build-plugins.sh +32 -0
  72. package/scripts/generate-upstream-evidence-manifest.mjs +50 -11
  73. 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 failed tracker read/write, claim, or binding blocks the work. Tracker availability must be proven; tool presence or stale session text is not access.
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
 
@@ -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
- const canonicalOriginUrls = new Set([
46
- "https://github.com/CodySwannGT/lisa.git",
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
- const originUrl = execFileSync("git", ["remote", "get-url", "origin"], {
52
- cwd: repoRoot,
53
- encoding: "utf8",
54
- }).trim();
55
- if (!canonicalOriginUrls.has(originUrl)) {
56
- throw new Error(`Refusing non-canonical Lisa origin: ${originUrl}`);
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="$repo_root/plugins/lisa/hooks/$guard.sh"
40
- [ -f "$script" ] || continue
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