@codyswann/lisa 3.18.0 → 3.18.2
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/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +6 -4
- package/dist/core/upstream-evidence-manifest.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/scripts/automation-run-record.mjs +37 -1
- package/plugins/lisa/scripts/cross-pollinate.mjs +37 -1
- package/plugins/lisa/scripts/design-source-gate.mjs +33 -2
- package/plugins/lisa/scripts/plugin-sync-explain.mjs +37 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/automation-run-record.mjs +37 -1
- package/plugins/lisa-agy/scripts/cross-pollinate.mjs +37 -1
- package/plugins/lisa-agy/scripts/design-source-gate.mjs +33 -2
- package/plugins/lisa-agy/scripts/plugin-sync-explain.mjs +37 -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/scripts/automation-run-record.mjs +37 -1
- package/plugins/lisa-copilot/scripts/cross-pollinate.mjs +37 -1
- package/plugins/lisa-copilot/scripts/design-source-gate.mjs +33 -2
- package/plugins/lisa-copilot/scripts/plugin-sync-explain.mjs +37 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/scripts/automation-run-record.mjs +37 -1
- package/plugins/lisa-cursor/scripts/cross-pollinate.mjs +37 -1
- package/plugins/lisa-cursor/scripts/design-source-gate.mjs +33 -2
- package/plugins/lisa-cursor/scripts/plugin-sync-explain.mjs +37 -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/scripts/automation-run-record.mjs +37 -1
- package/plugins/src/base/scripts/cross-pollinate.mjs +37 -1
- package/plugins/src/base/scripts/design-source-gate.mjs +33 -2
- package/plugins/src/base/scripts/plugin-sync-explain.mjs +37 -1
package/package.json
CHANGED
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
}
|
|
130
130
|
},
|
|
131
131
|
"name": "@codyswann/lisa",
|
|
132
|
-
"version": "3.18.
|
|
132
|
+
"version": "3.18.2",
|
|
133
133
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
134
134
|
"main": "dist/index.js",
|
|
135
135
|
"exports": {
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
|
+
import { realpathSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
11
13
|
|
|
12
14
|
export const AUTOMATION_RUN_OUTCOMES = [
|
|
13
15
|
"nothing-needed",
|
|
@@ -396,7 +398,41 @@ export async function runAutomationRunRecordCli(argv) {
|
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
// CLI entrypoint.
|
|
399
|
-
|
|
401
|
+
/**
|
|
402
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
403
|
+
*
|
|
404
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
405
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
406
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
407
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
408
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
409
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
410
|
+
* exotic one.
|
|
411
|
+
*
|
|
412
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
413
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
414
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
415
|
+
*
|
|
416
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
417
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
418
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
419
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
420
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
421
|
+
* not the path this module came through.
|
|
422
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
423
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
424
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
425
|
+
*/
|
|
426
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
427
|
+
if (!argv1) return false;
|
|
428
|
+
try {
|
|
429
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (invokedAsScript(import.meta.url)) {
|
|
400
436
|
runAutomationRunRecordCli(process.argv.slice(2)).then(
|
|
401
437
|
code => {
|
|
402
438
|
process.exitCode = code;
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
import { createHash } from "node:crypto";
|
|
38
38
|
import fs from "node:fs";
|
|
39
39
|
import path from "node:path";
|
|
40
|
+
import { realpathSync } from "node:fs";
|
|
41
|
+
import { fileURLToPath } from "node:url";
|
|
40
42
|
|
|
41
43
|
const LOCKFILE_REL = path.join(".lisa", "cross-pollination.lock.json");
|
|
42
44
|
const LOCK_VERSION = 1;
|
|
@@ -704,7 +706,41 @@ export function renderReport(p, result) {
|
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
// CLI entrypoint.
|
|
707
|
-
|
|
709
|
+
/**
|
|
710
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
711
|
+
*
|
|
712
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
713
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
714
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
715
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
716
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
717
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
718
|
+
* exotic one.
|
|
719
|
+
*
|
|
720
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
721
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
722
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
723
|
+
*
|
|
724
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
725
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
726
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
727
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
728
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
729
|
+
* not the path this module came through.
|
|
730
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
731
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
732
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
733
|
+
*/
|
|
734
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
735
|
+
if (!argv1) return false;
|
|
736
|
+
try {
|
|
737
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
738
|
+
} catch {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (invokedAsScript(import.meta.url)) {
|
|
708
744
|
const args = process.argv.slice(2);
|
|
709
745
|
const root = path.resolve(args.find(a => !a.startsWith("-")) ?? ".");
|
|
710
746
|
const dryRun = args.includes("--dry-run") || !args.includes("--write");
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
* Exit 0 = PASS, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
36
36
|
*/
|
|
37
37
|
import { execFileSync } from "node:child_process";
|
|
38
|
-
import { readFileSync } from "node:fs";
|
|
38
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
39
40
|
|
|
40
41
|
/** The one designated marker for UI deliberately not captured in Figma. */
|
|
41
42
|
export const DESIGN_SOURCE_NONE_MARKER = "DESIGN-SOURCE: none — not in Figma";
|
|
@@ -534,6 +535,36 @@ export function runCli(argv) {
|
|
|
534
535
|
return result.verdict === "PASS" ? 0 : 1;
|
|
535
536
|
}
|
|
536
537
|
|
|
537
|
-
|
|
538
|
+
/**
|
|
539
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
540
|
+
*
|
|
541
|
+
* The previous spelling tested whether `process.argv[1]` ENDED WITH this
|
|
542
|
+
* module's basename, which is looser still than the `file://` comparison the
|
|
543
|
+
* sibling modules used: any path ending in `design-source-gate.mjs` satisfied
|
|
544
|
+
* it, including a different copy of this file in another checkout, and a
|
|
545
|
+
* rename silently turned the guard off with nothing to notice.
|
|
546
|
+
*
|
|
547
|
+
* Both sides are realpath'd instead. Reached through a symlinked checkout, a
|
|
548
|
+
* git worktree, or a `/tmp` path on macOS the naive comparisons disagree, the
|
|
549
|
+
* body never runs, and the process exits 0 having done nothing — and every
|
|
550
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path.
|
|
551
|
+
*
|
|
552
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
553
|
+
* has no `./lib/` to resolve against. Same rule and reasoning as
|
|
554
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
555
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
556
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
557
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
558
|
+
*/
|
|
559
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
560
|
+
if (!argv1) return false;
|
|
561
|
+
try {
|
|
562
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
563
|
+
} catch {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (invokedAsScript(import.meta.url)) {
|
|
538
569
|
process.exit(runCli(process.argv.slice(2)));
|
|
539
570
|
}
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
import { tmpdir } from "node:os";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import process from "node:process";
|
|
22
|
+
import { realpathSync } from "node:fs";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
22
24
|
|
|
23
25
|
export const PLUGIN_SYNC_CLASSIFICATIONS = [
|
|
24
26
|
"SOURCE_NOT_BUILT",
|
|
@@ -556,7 +558,41 @@ function linkedWorktreeGitDir(root) {
|
|
|
556
558
|
return path.isAbsolute(gitDir) ? gitDir : path.resolve(root, gitDir);
|
|
557
559
|
}
|
|
558
560
|
|
|
559
|
-
|
|
561
|
+
/**
|
|
562
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
563
|
+
*
|
|
564
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
565
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
566
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
567
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
568
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
569
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
570
|
+
* exotic one.
|
|
571
|
+
*
|
|
572
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
573
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
574
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
575
|
+
*
|
|
576
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
577
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
578
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
579
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
580
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
581
|
+
* not the path this module came through.
|
|
582
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
583
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
584
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
585
|
+
*/
|
|
586
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
587
|
+
if (!argv1) return false;
|
|
588
|
+
try {
|
|
589
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
590
|
+
} catch {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (invokedAsScript(import.meta.url)) {
|
|
560
596
|
try {
|
|
561
597
|
const report = explainPluginSync(process.argv[2] ?? process.cwd());
|
|
562
598
|
process.stdout.write(report.text);
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
|
+
import { realpathSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
11
13
|
|
|
12
14
|
export const AUTOMATION_RUN_OUTCOMES = [
|
|
13
15
|
"nothing-needed",
|
|
@@ -396,7 +398,41 @@ export async function runAutomationRunRecordCli(argv) {
|
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
// CLI entrypoint.
|
|
399
|
-
|
|
401
|
+
/**
|
|
402
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
403
|
+
*
|
|
404
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
405
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
406
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
407
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
408
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
409
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
410
|
+
* exotic one.
|
|
411
|
+
*
|
|
412
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
413
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
414
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
415
|
+
*
|
|
416
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
417
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
418
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
419
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
420
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
421
|
+
* not the path this module came through.
|
|
422
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
423
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
424
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
425
|
+
*/
|
|
426
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
427
|
+
if (!argv1) return false;
|
|
428
|
+
try {
|
|
429
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (invokedAsScript(import.meta.url)) {
|
|
400
436
|
runAutomationRunRecordCli(process.argv.slice(2)).then(
|
|
401
437
|
code => {
|
|
402
438
|
process.exitCode = code;
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
import { createHash } from "node:crypto";
|
|
38
38
|
import fs from "node:fs";
|
|
39
39
|
import path from "node:path";
|
|
40
|
+
import { realpathSync } from "node:fs";
|
|
41
|
+
import { fileURLToPath } from "node:url";
|
|
40
42
|
|
|
41
43
|
const LOCKFILE_REL = path.join(".lisa", "cross-pollination.lock.json");
|
|
42
44
|
const LOCK_VERSION = 1;
|
|
@@ -704,7 +706,41 @@ export function renderReport(p, result) {
|
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
// CLI entrypoint.
|
|
707
|
-
|
|
709
|
+
/**
|
|
710
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
711
|
+
*
|
|
712
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
713
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
714
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
715
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
716
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
717
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
718
|
+
* exotic one.
|
|
719
|
+
*
|
|
720
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
721
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
722
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
723
|
+
*
|
|
724
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
725
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
726
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
727
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
728
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
729
|
+
* not the path this module came through.
|
|
730
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
731
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
732
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
733
|
+
*/
|
|
734
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
735
|
+
if (!argv1) return false;
|
|
736
|
+
try {
|
|
737
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
738
|
+
} catch {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (invokedAsScript(import.meta.url)) {
|
|
708
744
|
const args = process.argv.slice(2);
|
|
709
745
|
const root = path.resolve(args.find(a => !a.startsWith("-")) ?? ".");
|
|
710
746
|
const dryRun = args.includes("--dry-run") || !args.includes("--write");
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
* Exit 0 = PASS, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
36
36
|
*/
|
|
37
37
|
import { execFileSync } from "node:child_process";
|
|
38
|
-
import { readFileSync } from "node:fs";
|
|
38
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
39
40
|
|
|
40
41
|
/** The one designated marker for UI deliberately not captured in Figma. */
|
|
41
42
|
export const DESIGN_SOURCE_NONE_MARKER = "DESIGN-SOURCE: none — not in Figma";
|
|
@@ -534,6 +535,36 @@ export function runCli(argv) {
|
|
|
534
535
|
return result.verdict === "PASS" ? 0 : 1;
|
|
535
536
|
}
|
|
536
537
|
|
|
537
|
-
|
|
538
|
+
/**
|
|
539
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
540
|
+
*
|
|
541
|
+
* The previous spelling tested whether `process.argv[1]` ENDED WITH this
|
|
542
|
+
* module's basename, which is looser still than the `file://` comparison the
|
|
543
|
+
* sibling modules used: any path ending in `design-source-gate.mjs` satisfied
|
|
544
|
+
* it, including a different copy of this file in another checkout, and a
|
|
545
|
+
* rename silently turned the guard off with nothing to notice.
|
|
546
|
+
*
|
|
547
|
+
* Both sides are realpath'd instead. Reached through a symlinked checkout, a
|
|
548
|
+
* git worktree, or a `/tmp` path on macOS the naive comparisons disagree, the
|
|
549
|
+
* body never runs, and the process exits 0 having done nothing — and every
|
|
550
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path.
|
|
551
|
+
*
|
|
552
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
553
|
+
* has no `./lib/` to resolve against. Same rule and reasoning as
|
|
554
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
555
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
556
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
557
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
558
|
+
*/
|
|
559
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
560
|
+
if (!argv1) return false;
|
|
561
|
+
try {
|
|
562
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
563
|
+
} catch {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (invokedAsScript(import.meta.url)) {
|
|
538
569
|
process.exit(runCli(process.argv.slice(2)));
|
|
539
570
|
}
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
import { tmpdir } from "node:os";
|
|
20
20
|
import path from "node:path";
|
|
21
21
|
import process from "node:process";
|
|
22
|
+
import { realpathSync } from "node:fs";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
22
24
|
|
|
23
25
|
export const PLUGIN_SYNC_CLASSIFICATIONS = [
|
|
24
26
|
"SOURCE_NOT_BUILT",
|
|
@@ -556,7 +558,41 @@ function linkedWorktreeGitDir(root) {
|
|
|
556
558
|
return path.isAbsolute(gitDir) ? gitDir : path.resolve(root, gitDir);
|
|
557
559
|
}
|
|
558
560
|
|
|
559
|
-
|
|
561
|
+
/**
|
|
562
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
563
|
+
*
|
|
564
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
565
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
566
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
567
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
568
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
569
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
570
|
+
* exotic one.
|
|
571
|
+
*
|
|
572
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
573
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
574
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
575
|
+
*
|
|
576
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
577
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
578
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
579
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
580
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
581
|
+
* not the path this module came through.
|
|
582
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
583
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
584
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
585
|
+
*/
|
|
586
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
587
|
+
if (!argv1) return false;
|
|
588
|
+
try {
|
|
589
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
590
|
+
} catch {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
if (invokedAsScript(import.meta.url)) {
|
|
560
596
|
try {
|
|
561
597
|
const report = explainPluginSync(process.argv[2] ?? process.cwd());
|
|
562
598
|
process.stdout.write(report.text);
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
10
10
|
import path from "node:path";
|
|
11
|
+
import { realpathSync } from "node:fs";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
11
13
|
|
|
12
14
|
export const AUTOMATION_RUN_OUTCOMES = [
|
|
13
15
|
"nothing-needed",
|
|
@@ -396,7 +398,41 @@ export async function runAutomationRunRecordCli(argv) {
|
|
|
396
398
|
}
|
|
397
399
|
|
|
398
400
|
// CLI entrypoint.
|
|
399
|
-
|
|
401
|
+
/**
|
|
402
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
403
|
+
*
|
|
404
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
405
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
406
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
407
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
408
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
409
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
410
|
+
* exotic one.
|
|
411
|
+
*
|
|
412
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
413
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
414
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
415
|
+
*
|
|
416
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
417
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
418
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
419
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
420
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
421
|
+
* not the path this module came through.
|
|
422
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
423
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
424
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
425
|
+
*/
|
|
426
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
427
|
+
if (!argv1) return false;
|
|
428
|
+
try {
|
|
429
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
430
|
+
} catch {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (invokedAsScript(import.meta.url)) {
|
|
400
436
|
runAutomationRunRecordCli(process.argv.slice(2)).then(
|
|
401
437
|
code => {
|
|
402
438
|
process.exitCode = code;
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
import { createHash } from "node:crypto";
|
|
38
38
|
import fs from "node:fs";
|
|
39
39
|
import path from "node:path";
|
|
40
|
+
import { realpathSync } from "node:fs";
|
|
41
|
+
import { fileURLToPath } from "node:url";
|
|
40
42
|
|
|
41
43
|
const LOCKFILE_REL = path.join(".lisa", "cross-pollination.lock.json");
|
|
42
44
|
const LOCK_VERSION = 1;
|
|
@@ -704,7 +706,41 @@ export function renderReport(p, result) {
|
|
|
704
706
|
}
|
|
705
707
|
|
|
706
708
|
// CLI entrypoint.
|
|
707
|
-
|
|
709
|
+
/**
|
|
710
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
711
|
+
*
|
|
712
|
+
* Both sides are realpath'd. The previous spelling compared `import.meta.url`
|
|
713
|
+
* against a `file://` string built from `process.argv[1]`, which pits a real
|
|
714
|
+
* path against whatever the caller typed — so reached through a symlinked
|
|
715
|
+
* checkout, a git worktree, or a `/tmp` path on macOS the two disagreed, the
|
|
716
|
+
* body never ran, and the process exited 0 having done nothing. Every
|
|
717
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path, not an
|
|
718
|
+
* exotic one.
|
|
719
|
+
*
|
|
720
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
721
|
+
* has no `./lib/` to resolve against. Same rule and same reasoning as
|
|
722
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
723
|
+
*
|
|
724
|
+
* Realpathing BOTH sides matters under `--preserve-symlinks-main`, which tells
|
|
725
|
+
* node not to resolve the main entry: normalizing only `argv[1]` then compares
|
|
726
|
+
* a real path against a symlinked one and answers false for an entry point that
|
|
727
|
+
* WAS invoked directly. Any resolution error returns false — node loaded the
|
|
728
|
+
* entry from that path moments earlier, so a path that will not resolve now is
|
|
729
|
+
* not the path this module came through.
|
|
730
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
731
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
732
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
733
|
+
*/
|
|
734
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
735
|
+
if (!argv1) return false;
|
|
736
|
+
try {
|
|
737
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
738
|
+
} catch {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (invokedAsScript(import.meta.url)) {
|
|
708
744
|
const args = process.argv.slice(2);
|
|
709
745
|
const root = path.resolve(args.find(a => !a.startsWith("-")) ?? ".");
|
|
710
746
|
const dryRun = args.includes("--dry-run") || !args.includes("--write");
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
* Exit 0 = PASS, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
36
36
|
*/
|
|
37
37
|
import { execFileSync } from "node:child_process";
|
|
38
|
-
import { readFileSync } from "node:fs";
|
|
38
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
39
|
+
import { fileURLToPath } from "node:url";
|
|
39
40
|
|
|
40
41
|
/** The one designated marker for UI deliberately not captured in Figma. */
|
|
41
42
|
export const DESIGN_SOURCE_NONE_MARKER = "DESIGN-SOURCE: none — not in Figma";
|
|
@@ -534,6 +535,36 @@ export function runCli(argv) {
|
|
|
534
535
|
return result.verdict === "PASS" ? 0 : 1;
|
|
535
536
|
}
|
|
536
537
|
|
|
537
|
-
|
|
538
|
+
/**
|
|
539
|
+
* True when `moduleUrl` names the module node was asked to run.
|
|
540
|
+
*
|
|
541
|
+
* The previous spelling tested whether `process.argv[1]` ENDED WITH this
|
|
542
|
+
* module's basename, which is looser still than the `file://` comparison the
|
|
543
|
+
* sibling modules used: any path ending in `design-source-gate.mjs` satisfied
|
|
544
|
+
* it, including a different copy of this file in another checkout, and a
|
|
545
|
+
* rename silently turned the guard off with nothing to notice.
|
|
546
|
+
*
|
|
547
|
+
* Both sides are realpath'd instead. Reached through a symlinked checkout, a
|
|
548
|
+
* git worktree, or a `/tmp` path on macOS the naive comparisons disagree, the
|
|
549
|
+
* body never runs, and the process exits 0 having done nothing — and every
|
|
550
|
+
* Lisa-driven agent runs in a worktree, so that is the routine path.
|
|
551
|
+
*
|
|
552
|
+
* Written out rather than imported: this ships inside a plugin payload, which
|
|
553
|
+
* has no `./lib/` to resolve against. Same rule and reasoning as
|
|
554
|
+
* `scripts/lib/invoked-as-script.mjs`.
|
|
555
|
+
* @param {string} moduleUrl - The caller's own `import.meta.url`.
|
|
556
|
+
* @param {string | undefined} [argv1] - Entry path; defaults to `process.argv[1]`.
|
|
557
|
+
* @returns {boolean} Whether the caller should run its CLI body.
|
|
558
|
+
*/
|
|
559
|
+
export function invokedAsScript(moduleUrl, argv1 = process.argv[1]) {
|
|
560
|
+
if (!argv1) return false;
|
|
561
|
+
try {
|
|
562
|
+
return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
|
|
563
|
+
} catch {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (invokedAsScript(import.meta.url)) {
|
|
538
569
|
process.exit(runCli(process.argv.slice(2)));
|
|
539
570
|
}
|