@codyswann/lisa 2.259.4 → 2.260.0
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/cli/file-upstream-cmd.d.ts +28 -0
- package/dist/cli/file-upstream-cmd.d.ts.map +1 -0
- package/dist/cli/file-upstream-cmd.js +231 -0
- package/dist/cli/file-upstream-cmd.js.map +1 -0
- package/dist/cli/gate-commands.d.ts +17 -0
- package/dist/cli/gate-commands.d.ts.map +1 -0
- package/dist/cli/gate-commands.js +47 -0
- package/dist/cli/gate-commands.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +6 -27
- package/dist/cli/index.js.map +1 -1
- package/dist/core/upstream-attribution-body.d.ts +38 -25
- package/dist/core/upstream-attribution-body.d.ts.map +1 -1
- package/dist/core/upstream-attribution-body.js +515 -155
- package/dist/core/upstream-attribution-body.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts +7 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -0
- package/dist/core/upstream-evidence-manifest.js +11623 -0
- package/dist/core/upstream-evidence-manifest.js.map +1 -0
- package/package.json +4 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +32 -8
- package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +32 -8
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +32 -8
- 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/skills/lisa-persist-learning/SKILL.md +32 -8
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +32 -8
- 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/skills/lisa-persist-learning/SKILL.md +32 -8
- package/scripts/generate-upstream-evidence-manifest.mjs +157 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.260.0",
|
|
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": "2.
|
|
3
|
+
"version": "2.260.0",
|
|
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": "2.
|
|
3
|
+
"version": "2.260.0",
|
|
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": "2.
|
|
3
|
+
"version": "2.260.0",
|
|
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": "2.
|
|
3
|
+
"version": "2.260.0",
|
|
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"
|
|
@@ -90,19 +90,19 @@ This disposition completes the SLL-5 loop (#1583): on a Lisa-attributed failure
|
|
|
90
90
|
root-cause-key = <lisa-surface>#<failure-class>
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
- `<lisa-surface>` — the Lisa-relative path of the surface at fault (e.g. `plugins/src/base/skills/lisa-doctor/SKILL.md`, `typescript/copy-overwrite/.github/workflows/quality.yml`)
|
|
94
|
-
- `<failure-class>` —
|
|
93
|
+
- `<lisa-surface>` — the exact public Lisa-relative path of the surface at fault (e.g. `plugins/src/base/skills/lisa-doctor/SKILL.md`, `typescript/copy-overwrite/.github/workflows/quality.yml`). Canonical names, aliases, host paths, and unmanifested paths are prohibited.
|
|
94
|
+
- `<failure-class>` — exactly one exported closed value: `access-control-failure`, `agent-parity-regression`, `configuration-regression`, `data-integrity-failure`, `dependency-regression`, `generated-artifact-regression`, `installation-regression`, `observability-gap`, `pagination-truncation`, `performance-regression`, `public-data-exposure`, `release-regression`, `runtime-regression`, `stale-artifact-overwrite`, `test-coverage-gap`, `validation-gap`, or `workflow-contract-violation`.
|
|
95
95
|
- Normalize: lowercase, trim, collapse every whitespace run to a single `-`. The key must contain no host-project name, no local issue number, and no fingerprint — those vary per project and would defeat fleet-wide dedupe.
|
|
96
96
|
|
|
97
97
|
4. **Enforce the per-run cap.** Resolve `hardening.maxUpstreamFilingsPerRun` from `.lisa.config.json` (default `5` — a conservative bound modeled on `lisa-repair-intake`'s `max_candidates` precedent). Count every upstream create **and** update this run performs; once the cap is reached, drop the remaining candidates and **note each dropped candidate visibly** (in the run summary, naming its root-cause key) — never queue a spam burst and never drop silently. A later run picks the dropped candidates up idempotently.
|
|
98
98
|
|
|
99
|
-
5. **Evidence redaction (binding).** The upstream repo is PUBLIC by default (`hardening.upstreamRepo` → `CodySwannGT/lisa`) and this filing runs headless on crons — treat every drafted upstream body and comment as world-readable:
|
|
99
|
+
5. **Evidence redaction (binding).** The upstream repo is PUBLIC by default (`hardening.upstreamRepo` → `CodySwannGT/lisa`) and this filing runs headless on crons — treat every drafted upstream body and comment as world-readable. The PRIMARY control is the **allowlist projection** in step 6: `bunx @codyswann/lisa file-upstream` calls the sole `buildUpstreamAttributionIssueBody` export from `@codyswann/lisa/learnings`, so content outside its enumerated fields is structurally incapable of reaching the public document. The rules below bind the FIELDS supplied to that command; the closing scan is a defense-in-depth backstop, never the primary control:
|
|
100
100
|
|
|
101
101
|
- Quote ONLY Lisa-owned surface text: template/rule/skill/hook excerpts and upstream commit references. The reproduction must be REDACTED — generic placeholders, never the host project's real values.
|
|
102
102
|
- Never paste host environment values, tokens/credentials, connection strings, API keys, PII (names, emails, customer data), or proprietary host code/payloads.
|
|
103
|
-
- The evidence chain names the Lisa surface and the failure class — never project payloads.
|
|
104
|
-
-
|
|
105
|
-
-
|
|
103
|
+
- The evidence chain names the Lisa surface and the failure class — never project payloads. Keep any host-project issue link only in the private local trace; it is never supplied to or emitted by the public builder.
|
|
104
|
+
- Use only these exact generic placeholders: `<host-project>`, `<env-value>`, `<credential>`, `<connection-string>`, `<pii>`, `<host-payload>`, `<path>`, `<identifier>`. A project-specific placeholder is host prose and must be rejected.
|
|
105
|
+
- **Backstop (defense in depth, never the primary control).** Before filing or commenting, scan the projected document for common secret shapes — `key=value` pairs with high-entropy values, token prefixes (`AKIA`, `ghp_`, `xox`), email addresses — and reject on a match. To strip on match, remove the offending INPUT field and re-run `file-upstream`; never strip or edit the generated output itself. Non-allowlisted fields must reject before filing rather than be silently dropped. When in doubt, leave it out: a thinner upstream document is recoverable; a leaked secret is not.
|
|
106
106
|
|
|
107
107
|
6. **Dedupe by marker, then file or update.** The upstream marker is:
|
|
108
108
|
|
|
@@ -112,8 +112,32 @@ This disposition completes the SLL-5 loop (#1583): on a Lisa-attributed failure
|
|
|
112
112
|
|
|
113
113
|
Resolve the upstream repo from `.lisa.config.json` `hardening.upstreamRepo` (default `CodySwannGT/lisa`). Search **all issue states** for an existing issue carrying the marker — a closed marker-bearing ticket still owns this root cause, and searching only open issues would mint a duplicate the moment the original closes. Match on the **MARKER, never the title** — with the same eventual-consistency guard as above (`gh issue list -R <upstream> --state all --search '"<marker>" in:body' --json number,state,url`, and when the search index returns nothing, also `gh issue list -R <upstream> --state all --json number,state,body` and grep the bodies for the marker before concluding no ticket exists).
|
|
114
114
|
|
|
115
|
-
- **No existing ticket** →
|
|
116
|
-
|
|
115
|
+
- **No existing ticket** → compose the body EXCLUSIVELY through the executable builder, then file its stdout verbatim via `lisa-github-write-issue` targeting the upstream repo with the `self-hardening` label:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bunx @codyswann/lisa file-upstream --input filing-event.json # or pipe the JSON on stdin
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Never assemble the public body as free-form prose.** Public composition happens through the builder, never by free-form prose assembly. The builder owns the three-audience description and the redacted evidence chain (Lisa-owned text only). Do not hand-write either section, name an affected project in prose, or edit the builder's output after generation. Supply only this JSON shape; host-project issue URLs remain private local-trace data and are never accepted by the public builder:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"documentKind": "issue",
|
|
126
|
+
"lisaSurface": "plugins/src/base/skills/lisa-doctor/SKILL.md",
|
|
127
|
+
"failureClass": "stale-artifact-overwrite",
|
|
128
|
+
"lisaOwnedExcerpts": [
|
|
129
|
+
{
|
|
130
|
+
"file": "plugins/src/base/skills/lisa-doctor/SKILL.md",
|
|
131
|
+
"text": "<verbatim Lisa-owned text>"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"upstreamCommitRefs": ["<full 40-character public-origin SHA>"],
|
|
135
|
+
"redactedPlaceholders": ["<host-project>", "<env-value>"]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Every excerpt is verified against the installed package's Lisa-owned source and every commit against the public origin. Callers cannot supply a verifier or Lisa root. Anything outside the allowlist is REJECTED by field name with empty stdout and a non-zero exit; fix or remove the offending input field and re-run the command, never route around it. The builder emits **exactly one** dedupe marker; **never write a markerless body** — it permanently breaks all future dedupe.
|
|
140
|
+
- **Existing ticket (open or closed)** → this is a repeat encounter: comment the new occurrence on the existing issue with this project's evidence. The comment is projected through the same builder: run `bunx @codyswann/lisa file-upstream` with the same allowlisted fields plus exactly `"documentKind": "occurrence"` and `"occurrenceFingerprint": "<fingerprint>"`. The supplied fingerprint is only a validated seed: the builder hashes it and emits a different deterministic `sll4-<12 lowercase hex>` marker. Use the marker in the builder's stdout — never the supplied literal — to search existing issue comments for a duplicate, then post stdout verbatim only when that emitted marker is absent. Free-form occurrence prose is prohibited, and post-generation edits are prohibited. Never open a second issue, and never match on the title — evidence compounds on one ticket. When the match is **CLOSED**, still comment the occurrence there and reference it in the local trace instead of filing a duplicate; do not reopen it yourself — recurrence evidence on a closed ticket signals the shipped fix may not cover this case, and reopening is the upstream maintainer's call.
|
|
117
141
|
|
|
118
142
|
7. **Leave the local trace — a note, never a rule.** Post one follow-up comment on the triggering issue linking the upstream ticket:
|
|
119
143
|
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Generate the exact hash-pinned allowlist for public upstream evidence. */
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
|
|
8
|
+
const repoRoot = path.resolve(import.meta.dirname, "..");
|
|
9
|
+
const outputPath = path.join(
|
|
10
|
+
repoRoot,
|
|
11
|
+
"src/core/upstream-evidence-manifest.ts"
|
|
12
|
+
);
|
|
13
|
+
const packagedEvidencePrefixes = [
|
|
14
|
+
"plugins/src/",
|
|
15
|
+
"all/",
|
|
16
|
+
"cdk/",
|
|
17
|
+
"expo/",
|
|
18
|
+
"eslint-plugin-code-organization/",
|
|
19
|
+
"eslint-plugin-component-structure/",
|
|
20
|
+
"eslint-plugin-phaser/",
|
|
21
|
+
"eslint-plugin-ui-standards/",
|
|
22
|
+
"harper-fabric/",
|
|
23
|
+
"nestjs/",
|
|
24
|
+
"npm-package/",
|
|
25
|
+
"oxlint/",
|
|
26
|
+
"phaser/",
|
|
27
|
+
"rails/",
|
|
28
|
+
"scripts/",
|
|
29
|
+
"tsconfig/",
|
|
30
|
+
"typescript/",
|
|
31
|
+
"ui/",
|
|
32
|
+
];
|
|
33
|
+
const forbiddenSegments = new Set([
|
|
34
|
+
".claude-plugin",
|
|
35
|
+
".git",
|
|
36
|
+
".lisa",
|
|
37
|
+
".mcp",
|
|
38
|
+
"node_modules",
|
|
39
|
+
]);
|
|
40
|
+
const forbiddenBasenames = new Set([
|
|
41
|
+
".lisa.config.json",
|
|
42
|
+
".mcp.json",
|
|
43
|
+
"audit.local",
|
|
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
|
+
]);
|
|
50
|
+
|
|
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}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const tracked = execFileSync("git", ["ls-files", "-z"], {
|
|
60
|
+
cwd: repoRoot,
|
|
61
|
+
encoding: "utf8",
|
|
62
|
+
})
|
|
63
|
+
.split("\0")
|
|
64
|
+
.filter(Boolean);
|
|
65
|
+
const explicitlyIncluded = ["scripts/generate-upstream-evidence-manifest.mjs"];
|
|
66
|
+
const publicSurfaceMembers = [...new Set([...tracked, ...explicitlyIncluded])]
|
|
67
|
+
.filter(file => file !== "src/core/upstream-evidence-manifest.ts")
|
|
68
|
+
.filter(file => {
|
|
69
|
+
const segments = file.split("/");
|
|
70
|
+
const basename = segments.at(-1) ?? "";
|
|
71
|
+
return (
|
|
72
|
+
!segments.some(segment => forbiddenSegments.has(segment)) &&
|
|
73
|
+
!forbiddenBasenames.has(basename) &&
|
|
74
|
+
!basename.endsWith(".local")
|
|
75
|
+
);
|
|
76
|
+
})
|
|
77
|
+
.sort();
|
|
78
|
+
const evidenceMembers = publicSurfaceMembers.filter(file =>
|
|
79
|
+
packagedEvidencePrefixes.some(prefix => file.startsWith(prefix))
|
|
80
|
+
);
|
|
81
|
+
const existingOutput = existsSync(outputPath)
|
|
82
|
+
? readFileSync(outputPath, "utf8")
|
|
83
|
+
: "";
|
|
84
|
+
const existingPublicCommits = [
|
|
85
|
+
...existingOutput.matchAll(
|
|
86
|
+
/^\s+(?:"([0-9][a-f0-9]{39})"|([a-f][a-f0-9]{39})):\s+true,$/gmu
|
|
87
|
+
),
|
|
88
|
+
]
|
|
89
|
+
.map(match => match[1] ?? match[2] ?? "")
|
|
90
|
+
.filter(Boolean);
|
|
91
|
+
const refreshPublicCommits = process.argv.includes("--refresh-public-commits");
|
|
92
|
+
const discoveredPublicCommits = refreshPublicCommits
|
|
93
|
+
? execFileSync("git", ["rev-list", "--remotes=origin"], {
|
|
94
|
+
cwd: repoRoot,
|
|
95
|
+
encoding: "utf8",
|
|
96
|
+
})
|
|
97
|
+
.split("\n")
|
|
98
|
+
.filter(commit => /^[a-f0-9]{40}$/.test(commit))
|
|
99
|
+
: [];
|
|
100
|
+
const publicCommits = [
|
|
101
|
+
...new Set([...existingPublicCommits, ...discoveredPublicCommits]),
|
|
102
|
+
].sort();
|
|
103
|
+
|
|
104
|
+
if (publicSurfaceMembers.length === 0 || evidenceMembers.length === 0) {
|
|
105
|
+
throw new Error("Refusing to generate an empty upstream evidence manifest");
|
|
106
|
+
}
|
|
107
|
+
if (publicCommits.length === 0) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
"Refusing to generate an empty public origin commit manifest; rerun with --refresh-public-commits from a full canonical-origin clone"
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const formatObjectKey = value =>
|
|
114
|
+
/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value) ? value : JSON.stringify(value);
|
|
115
|
+
const surfaceEntries = publicSurfaceMembers.map(
|
|
116
|
+
file => ` ${formatObjectKey(file)}: true,`
|
|
117
|
+
);
|
|
118
|
+
const evidenceEntries = evidenceMembers.map(file => {
|
|
119
|
+
const digest = createHash("sha256")
|
|
120
|
+
.update(readFileSync(path.join(repoRoot, file)))
|
|
121
|
+
.digest("hex");
|
|
122
|
+
return ` ${JSON.stringify(file)}:\n ${JSON.stringify(digest)},`;
|
|
123
|
+
});
|
|
124
|
+
const commitEntries = publicCommits.map(commit => {
|
|
125
|
+
return ` ${formatObjectKey(commit)}: true,`;
|
|
126
|
+
});
|
|
127
|
+
const output = `/* eslint-disable max-lines -- generated exact public-evidence allowlist */
|
|
128
|
+
/** Generated by scripts/generate-upstream-evidence-manifest.mjs. Do not edit. */
|
|
129
|
+
export const UPSTREAM_EVIDENCE_MANIFEST: Readonly<Record<string, string>> =
|
|
130
|
+
Object.freeze({
|
|
131
|
+
${evidenceEntries.join("\n")}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
/** Exact paths tracked by the public Lisa repository at generation time. */
|
|
135
|
+
export const UPSTREAM_SURFACE_MANIFEST: Readonly<Record<string, true>> =
|
|
136
|
+
Object.freeze({
|
|
137
|
+
${surfaceEntries.join("\n")}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
/** Full commit SHAs reachable from public origin refs when this package was built. */
|
|
141
|
+
export const UPSTREAM_PUBLIC_COMMITS: Readonly<Record<string, true>> =
|
|
142
|
+
Object.freeze({
|
|
143
|
+
${commitEntries.join("\n")}
|
|
144
|
+
});
|
|
145
|
+
/* eslint-enable max-lines -- end generated exact public-evidence allowlist */
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
if (process.argv.includes("--check")) {
|
|
149
|
+
const current = readFileSync(outputPath, "utf8");
|
|
150
|
+
if (current !== output) {
|
|
151
|
+
throw new Error(
|
|
152
|
+
"src/core/upstream-evidence-manifest.ts is stale; run bun run build:upstream-evidence-manifest"
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
writeFileSync(outputPath, output);
|
|
157
|
+
}
|