@codyswann/lisa 4.4.8 → 4.4.9

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 (57) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +5 -2
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/package.json +1 -1
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa-agy/plugin.json +1 -1
  8. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  9. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  10. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  11. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-expo-agy/plugin.json +1 -1
  18. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  22. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  23. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  28. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  33. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  38. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-rails-agy/plugin.json +1 -1
  43. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  48. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  53. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  55. package/scripts/lib/plugin-cache-resolution.mjs +325 -0
  56. package/scripts/plugin-parity-drift.mjs +20 -253
  57. package/scripts/plugin-routing-validate.mjs +32 -68
@@ -39,16 +39,18 @@ import process from "node:process";
39
39
  import { fileURLToPath } from "node:url";
40
40
 
41
41
  import { invokedAsScript } from "./lib/invoked-as-script.mjs";
42
- import { compareSemver, isValidSemver } from "./plugin-parity-drift.mjs";
42
+ import {
43
+ compareSemver,
44
+ isDirectory,
45
+ isValidSemver,
46
+ resolveCurrentVersion,
47
+ } from "./lib/plugin-cache-resolution.mjs";
43
48
 
44
49
  const REPO_ROOT = path.resolve(
45
50
  path.dirname(fileURLToPath(import.meta.url)),
46
51
  ".."
47
52
  );
48
53
 
49
- /** A plugin name / marketplace token: `1*(ALPHA / DIGIT / "-" / "_")`. */
50
- const TOKEN_RE = /^[A-Za-z0-9_-]+$/;
51
-
52
54
  /** The non-Claude-native agents that every routing block must cover, exactly. */
53
55
  const AGENTS = ["agy", "codex", "copilot", "cursor"];
54
56
 
@@ -87,78 +89,40 @@ const QUOTE_LEN = 60;
87
89
  export class UsageError extends Error {}
88
90
 
89
91
  /**
90
- * True iff `target` is an existing directory.
92
+ * The max semver across a plugin's LIVE cache version subdirs, or `null`.
91
93
  *
92
- * @param {string} target - filesystem path.
93
- * @returns {boolean} whether `target` resolves to a directory.
94
- */
95
- function isDirectory(target) {
96
- try {
97
- return fs.statSync(target).isDirectory();
98
- } catch {
99
- return false;
100
- }
101
- }
102
-
103
- /**
104
- * Read a plugin manifest's `version` field, or `null` if unreadable / invalid.
94
+ * This used to walk the cache itself while importing only the semver helpers
95
+ * from the drift detector, which made the two scripts look like one resolver
96
+ * and behave like two. They disagreed about orphans: the detector was fixed to
97
+ * skip `.orphaned_at` directories (CodySwannGT/lisa#3085) and this walk was
98
+ * not, so it went on resolving a "current" version out of directories that were
99
+ * uninstalled ten days earlier — and the import argued the fix was already
100
+ * applied here (CodySwannGT/lisa#3093).
105
101
  *
106
- * @param {string} manifestPath - path to a `.claude-plugin/plugin.json`.
107
- * @returns {string | null} the manifest version string, or `null`.
108
- */
109
- function readManifestVersion(manifestPath) {
110
- try {
111
- const parsed = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
112
- return typeof parsed.version === "string" ? parsed.version : null;
113
- } catch {
114
- return null;
115
- }
116
- }
117
-
118
- /**
119
- * Resolve the max semver across a plugin's cache version subdirs, mirroring the
120
- * analyze-plugin Version-fallback rule: prefer each subdir's manifest `version`,
121
- * else fall back to the subdir NAME when it is itself semver (some plugins ship
122
- * no manifest version but a semver-named dir). Returns `null` when neither the
123
- * plugin nor any semver is present.
102
+ * It now calls the one resolver. `dirNameFallback` is this caller's single
103
+ * genuine difference, and it is named rather than implied: a semver DIRECTORY
104
+ * NAME stands in when a live version's manifest carries no usable `version`,
105
+ * which the drift detector deliberately does not do.
106
+ *
107
+ * ## Why both non-`ok` statuses collapse to `null` here
108
+ *
109
+ * The resolver distinguishes `not-installed` (no live directory at all) from
110
+ * `unresolved` (a live directory whose manifest will not parse), and that
111
+ * distinction is load-bearing in the detector's report. This caller has one
112
+ * question — "is there a version to compare against?" — and both answers are
113
+ * "no". The collapse is deliberate and local; the states stay distinct in the
114
+ * resolver so the detector can keep telling them apart.
124
115
  *
125
116
  * @param {string} cacheRoot - the installed-plugin cache root.
126
117
  * @param {string} name - plugin name.
127
118
  * @param {string} marketplace - marketplace id.
128
- * @returns {string | null} the max semver, or `null`.
119
+ * @returns {string | null} the max live semver, or `null`.
129
120
  */
130
121
  export function cacheMaxVersion(cacheRoot, name, marketplace) {
131
- if (!TOKEN_RE.test(name) || !TOKEN_RE.test(marketplace)) {
132
- return null;
133
- }
134
- const dir = path.join(cacheRoot, marketplace, name);
135
- if (!isDirectory(dir)) {
136
- return null;
137
- }
138
- const versions = [];
139
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
140
- if (!entry.isDirectory()) {
141
- continue;
142
- }
143
- const manifestVersion = readManifestVersion(
144
- path.join(dir, entry.name, ".claude-plugin", "plugin.json")
145
- );
146
- if (manifestVersion !== null && isValidSemver(manifestVersion)) {
147
- versions.push(manifestVersion);
148
- } else if (isValidSemver(entry.name)) {
149
- versions.push(entry.name);
150
- }
151
- }
152
- if (versions.length === 0) {
153
- return null;
154
- }
155
- // `versions` is non-empty (guarded above), so seeding with the first element
156
- // is exactly what the no-seed form did — and it cannot throw if that guard is
157
- // ever moved.
158
- return versions.reduce(
159
- (acc, v) => (compareSemver(v, acc) > 0 ? v : acc),
160
- versions[0]
161
- );
122
+ const resolved = resolveCurrentVersion(cacheRoot, name, marketplace, {
123
+ dirNameFallback: true,
124
+ });
125
+ return resolved.status === "ok" ? resolved.version : null;
162
126
  }
163
127
 
164
128
  /**