@codyswann/lisa 2.145.2 → 2.146.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/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-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-cursor/.claude-plugin/plugin.json +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-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/scripts/_wiki-lib.mjs +19 -0
- package/plugins/lisa-wiki/scripts/ingest-git.mjs +10 -9
- package/plugins/lisa-wiki/scripts/ingest-memory.mjs +14 -9
- package/plugins/lisa-wiki/scripts/ingest-roles.mjs +13 -3
- package/plugins/lisa-wiki/scripts/ingest_slack_channel.py +39 -7
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/scripts/_wiki-lib.mjs +19 -0
- package/plugins/lisa-wiki-agy/scripts/ingest-git.mjs +10 -9
- package/plugins/lisa-wiki-agy/scripts/ingest-memory.mjs +14 -9
- package/plugins/lisa-wiki-agy/scripts/ingest-roles.mjs +13 -3
- package/plugins/lisa-wiki-agy/scripts/ingest_slack_channel.py +39 -7
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/scripts/_wiki-lib.mjs +19 -0
- package/plugins/lisa-wiki-copilot/scripts/ingest-git.mjs +10 -9
- package/plugins/lisa-wiki-copilot/scripts/ingest-memory.mjs +14 -9
- package/plugins/lisa-wiki-copilot/scripts/ingest-roles.mjs +13 -3
- package/plugins/lisa-wiki-copilot/scripts/ingest_slack_channel.py +39 -7
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/scripts/_wiki-lib.mjs +19 -0
- package/plugins/lisa-wiki-cursor/scripts/ingest-git.mjs +10 -9
- package/plugins/lisa-wiki-cursor/scripts/ingest-memory.mjs +14 -9
- package/plugins/lisa-wiki-cursor/scripts/ingest-roles.mjs +13 -3
- package/plugins/lisa-wiki-cursor/scripts/ingest_slack_channel.py +39 -7
- package/plugins/src/wiki/scripts/_wiki-lib.mjs +19 -0
- package/plugins/src/wiki/scripts/ingest-git.mjs +10 -9
- package/plugins/src/wiki/scripts/ingest-memory.mjs +14 -9
- package/plugins/src/wiki/scripts/ingest-roles.mjs +13 -3
- package/plugins/src/wiki/scripts/ingest_slack_channel.py +39 -7
|
@@ -22,10 +22,37 @@ from typing import Any
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
TOKEN_PATTERNS = [
|
|
25
|
-
re.compile(r"xox[pbar]-[A-Za-z0-9-]+"),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
(re.compile(r"xox[pbar]-[A-Za-z0-9-]+"), "[REDACTED:OAUTH_TOKEN]"),
|
|
26
|
+
(
|
|
27
|
+
re.compile(r"(?i)bearer\s+[A-Za-z0-9._~+/=-]{20,}"),
|
|
28
|
+
"[REDACTED:OAUTH_TOKEN]",
|
|
29
|
+
),
|
|
30
|
+
(re.compile(r"AKIA[0-9A-Z]{16}"), "[REDACTED:API_KEY]"),
|
|
31
|
+
(
|
|
32
|
+
re.compile(
|
|
33
|
+
r"-----BEGIN [A-Z ]*PRIVATE KEY-----.*?-----END [A-Z ]*PRIVATE KEY-----",
|
|
34
|
+
re.S,
|
|
35
|
+
),
|
|
36
|
+
"[REDACTED:PRIVATE_KEY]",
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
re.compile(r"\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b"),
|
|
40
|
+
"[REDACTED:SSN]",
|
|
41
|
+
),
|
|
42
|
+
(
|
|
43
|
+
re.compile(
|
|
44
|
+
r"\b(?:password|passwd|pwd)\s*[:=]\s*(['\"]?)([^\s'\",;]{8,})\1",
|
|
45
|
+
re.I,
|
|
46
|
+
),
|
|
47
|
+
"[REDACTED:PASSWORD]",
|
|
48
|
+
),
|
|
49
|
+
(
|
|
50
|
+
re.compile(
|
|
51
|
+
r"\b(?:api[_-]?key|access[_-]?key|secret[_-]?key|client[_-]?secret)\s*[:=]\s*(['\"]?)([A-Za-z0-9._-]{20,})\1",
|
|
52
|
+
re.I,
|
|
53
|
+
),
|
|
54
|
+
"[REDACTED:API_KEY]",
|
|
55
|
+
),
|
|
29
56
|
]
|
|
30
57
|
|
|
31
58
|
|
|
@@ -49,8 +76,13 @@ def ts_from_input(value: str | None) -> str | None:
|
|
|
49
76
|
|
|
50
77
|
def redact(text: str) -> str:
|
|
51
78
|
out = text
|
|
52
|
-
for pattern in TOKEN_PATTERNS:
|
|
53
|
-
out = pattern.sub(
|
|
79
|
+
for pattern, replacement in TOKEN_PATTERNS:
|
|
80
|
+
out = pattern.sub(
|
|
81
|
+
lambda match: match.group(0).replace(match.group(2), replacement)
|
|
82
|
+
if len(match.groups()) >= 2
|
|
83
|
+
else replacement,
|
|
84
|
+
out,
|
|
85
|
+
)
|
|
54
86
|
return out
|
|
55
87
|
|
|
56
88
|
|
|
@@ -289,7 +321,7 @@ def main() -> int:
|
|
|
289
321
|
for reply in replies:
|
|
290
322
|
lines.extend(render_message(reply))
|
|
291
323
|
|
|
292
|
-
source_path.write_text("\n".join(lines), encoding="utf-8")
|
|
324
|
+
source_path.write_text(redact("\n".join(lines)), encoding="utf-8")
|
|
293
325
|
|
|
294
326
|
latest_ts = previous_state.get("latest_message_ts")
|
|
295
327
|
if messages:
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { sanitizeWikiSourceText } from "./wiki-safety.mjs";
|
|
8
9
|
|
|
9
10
|
/** Read and parse a JSON file, or return undefined if missing/invalid. */
|
|
10
11
|
export function readJsonSafe(file) {
|
|
@@ -59,6 +60,24 @@ export function walkFiles(dir, { ext } = {}) {
|
|
|
59
60
|
return out.sort();
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Sanitize a wiki source note immediately before it is persisted.
|
|
65
|
+
*
|
|
66
|
+
* Connectors should keep fetched raw material in memory or temporary locations
|
|
67
|
+
* outside the repo, render the source note, then call this helper at the final
|
|
68
|
+
* `wiki/sources/**` write boundary. The return value contains safe finding
|
|
69
|
+
* metadata only; callers can include it in handoff metadata when useful.
|
|
70
|
+
*/
|
|
71
|
+
export function writeSanitizedSourceNote(file, rawText, sourceMetadata = {}) {
|
|
72
|
+
const result = sanitizeWikiSourceText(rawText, {
|
|
73
|
+
...sourceMetadata,
|
|
74
|
+
path: sourceMetadata.path ?? file,
|
|
75
|
+
});
|
|
76
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
77
|
+
fs.writeFileSync(file, result.text);
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
/**
|
|
63
82
|
* Minimal frontmatter detector. Returns whether a leading `--- ... ---` block
|
|
64
83
|
* exists and the top-level keys it declares (enough to check required fields;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import fs from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import { execFileSync } from "node:child_process";
|
|
18
|
-
import { readJsonSafe,
|
|
18
|
+
import { readJsonSafe, writeSanitizedSourceNote } from "./_wiki-lib.mjs";
|
|
19
19
|
|
|
20
20
|
const argv = process.argv.slice(2);
|
|
21
21
|
const opt = (n, d) => {
|
|
@@ -53,12 +53,6 @@ const commitExists = c => {
|
|
|
53
53
|
return false;
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
-
const redact = t =>
|
|
57
|
-
SECRET_PATTERNS.reduce(
|
|
58
|
-
(acc, { re }) => acc.replace(new RegExp(re, "g"), "[REDACTED]"),
|
|
59
|
-
t
|
|
60
|
-
);
|
|
61
|
-
|
|
62
56
|
if (
|
|
63
57
|
!fs.existsSync(path.join(repo, ".git")) &&
|
|
64
58
|
!tryGit(["rev-parse", "--is-inside-work-tree"])
|
|
@@ -165,8 +159,11 @@ ${
|
|
|
165
159
|
}
|
|
166
160
|
`;
|
|
167
161
|
|
|
168
|
-
|
|
169
|
-
|
|
162
|
+
const safety = writeSanitizedSourceNote(notePath, note, {
|
|
163
|
+
sourceId: path.relative(process.cwd(), notePath),
|
|
164
|
+
sourceSystem: "git",
|
|
165
|
+
project: slug,
|
|
166
|
+
});
|
|
170
167
|
|
|
171
168
|
const meta = {
|
|
172
169
|
connector: "git",
|
|
@@ -174,6 +171,10 @@ const meta = {
|
|
|
174
171
|
ranAt: new Date().toISOString(),
|
|
175
172
|
proposedCursor: { lastCommit: head, lastPr },
|
|
176
173
|
sourceNotes: [path.relative(process.cwd(), notePath)],
|
|
174
|
+
safety: {
|
|
175
|
+
reviewRequired: safety.reviewRequired,
|
|
176
|
+
findings: safety.findings,
|
|
177
|
+
},
|
|
177
178
|
};
|
|
178
179
|
if (emitMeta) {
|
|
179
180
|
fs.mkdirSync(path.dirname(emitMeta), { recursive: true });
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
import fs from "node:fs";
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import os from "node:os";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
loadConfig,
|
|
20
|
+
walkFiles,
|
|
21
|
+
writeSanitizedSourceNote,
|
|
22
|
+
} from "./_wiki-lib.mjs";
|
|
19
23
|
|
|
20
24
|
const argv = process.argv.slice(2);
|
|
21
25
|
const opt = (n, d) => {
|
|
@@ -79,15 +83,10 @@ if (!(under(claudeMem) || under(projectCodexMem) || allowedRoots.some(under))) {
|
|
|
79
83
|
);
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
const redact = t =>
|
|
83
|
-
SECRET_PATTERNS.reduce(
|
|
84
|
-
(acc, { re }) => acc.replace(new RegExp(re, "g"), "[REDACTED]"),
|
|
85
|
-
t
|
|
86
|
-
);
|
|
87
86
|
const mdFiles = walkFiles(resolvedMem, { ext: ".md" });
|
|
88
87
|
const date = new Date().toISOString().slice(0, 10);
|
|
89
88
|
const entries = mdFiles.map(f => {
|
|
90
|
-
const body =
|
|
89
|
+
const body = fs.readFileSync(f, "utf8").trim();
|
|
91
90
|
return `### ${path.basename(f)}\n\n${body}`;
|
|
92
91
|
});
|
|
93
92
|
|
|
@@ -110,8 +109,10 @@ sensitivity: internal
|
|
|
110
109
|
${entries.join("\n\n") || "_(no memory files)_"}
|
|
111
110
|
`;
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const safety = writeSanitizedSourceNote(notePath, note, {
|
|
113
|
+
sourceId: path.relative(process.cwd(), notePath),
|
|
114
|
+
sourceSystem: "memory",
|
|
115
|
+
});
|
|
115
116
|
|
|
116
117
|
const meta = {
|
|
117
118
|
connector: "memory",
|
|
@@ -119,6 +120,10 @@ const meta = {
|
|
|
119
120
|
ranAt: new Date().toISOString(),
|
|
120
121
|
proposedCursor: { files: mdFiles.length, lastIngest: date },
|
|
121
122
|
sourceNotes: [path.relative(process.cwd(), notePath)],
|
|
123
|
+
safety: {
|
|
124
|
+
reviewRequired: safety.reviewRequired,
|
|
125
|
+
findings: safety.findings,
|
|
126
|
+
},
|
|
122
127
|
};
|
|
123
128
|
if (emitMeta) {
|
|
124
129
|
fs.mkdirSync(path.dirname(emitMeta), { recursive: true });
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import fs from "node:fs";
|
|
12
12
|
import path from "node:path";
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
loadConfig,
|
|
15
|
+
walkFiles,
|
|
16
|
+
writeSanitizedSourceNote,
|
|
17
|
+
} from "./_wiki-lib.mjs";
|
|
14
18
|
|
|
15
19
|
const argv = process.argv.slice(2);
|
|
16
20
|
const opt = (n, d) => {
|
|
@@ -61,8 +65,10 @@ ${rosterRows}
|
|
|
61
65
|
${staffPages.length ? staffPages.map(p => `- \`${path.relative(wikiRoot, p)}\``).join("\n") : "_(none)_"}
|
|
62
66
|
`;
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
const safety = writeSanitizedSourceNote(notePath, note, {
|
|
69
|
+
sourceId: path.relative(process.cwd(), notePath),
|
|
70
|
+
sourceSystem: "roles",
|
|
71
|
+
});
|
|
66
72
|
|
|
67
73
|
const meta = {
|
|
68
74
|
connector: "roles",
|
|
@@ -74,6 +80,10 @@ const meta = {
|
|
|
74
80
|
lastIngest: date,
|
|
75
81
|
},
|
|
76
82
|
sourceNotes: [path.relative(process.cwd(), notePath)],
|
|
83
|
+
safety: {
|
|
84
|
+
reviewRequired: safety.reviewRequired,
|
|
85
|
+
findings: safety.findings,
|
|
86
|
+
},
|
|
77
87
|
};
|
|
78
88
|
if (emitMeta) {
|
|
79
89
|
fs.mkdirSync(path.dirname(emitMeta), { recursive: true });
|
|
@@ -22,10 +22,37 @@ from typing import Any
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
TOKEN_PATTERNS = [
|
|
25
|
-
re.compile(r"xox[pbar]-[A-Za-z0-9-]+"),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
(re.compile(r"xox[pbar]-[A-Za-z0-9-]+"), "[REDACTED:OAUTH_TOKEN]"),
|
|
26
|
+
(
|
|
27
|
+
re.compile(r"(?i)bearer\s+[A-Za-z0-9._~+/=-]{20,}"),
|
|
28
|
+
"[REDACTED:OAUTH_TOKEN]",
|
|
29
|
+
),
|
|
30
|
+
(re.compile(r"AKIA[0-9A-Z]{16}"), "[REDACTED:API_KEY]"),
|
|
31
|
+
(
|
|
32
|
+
re.compile(
|
|
33
|
+
r"-----BEGIN [A-Z ]*PRIVATE KEY-----.*?-----END [A-Z ]*PRIVATE KEY-----",
|
|
34
|
+
re.S,
|
|
35
|
+
),
|
|
36
|
+
"[REDACTED:PRIVATE_KEY]",
|
|
37
|
+
),
|
|
38
|
+
(
|
|
39
|
+
re.compile(r"\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b"),
|
|
40
|
+
"[REDACTED:SSN]",
|
|
41
|
+
),
|
|
42
|
+
(
|
|
43
|
+
re.compile(
|
|
44
|
+
r"\b(?:password|passwd|pwd)\s*[:=]\s*(['\"]?)([^\s'\",;]{8,})\1",
|
|
45
|
+
re.I,
|
|
46
|
+
),
|
|
47
|
+
"[REDACTED:PASSWORD]",
|
|
48
|
+
),
|
|
49
|
+
(
|
|
50
|
+
re.compile(
|
|
51
|
+
r"\b(?:api[_-]?key|access[_-]?key|secret[_-]?key|client[_-]?secret)\s*[:=]\s*(['\"]?)([A-Za-z0-9._-]{20,})\1",
|
|
52
|
+
re.I,
|
|
53
|
+
),
|
|
54
|
+
"[REDACTED:API_KEY]",
|
|
55
|
+
),
|
|
29
56
|
]
|
|
30
57
|
|
|
31
58
|
|
|
@@ -49,8 +76,13 @@ def ts_from_input(value: str | None) -> str | None:
|
|
|
49
76
|
|
|
50
77
|
def redact(text: str) -> str:
|
|
51
78
|
out = text
|
|
52
|
-
for pattern in TOKEN_PATTERNS:
|
|
53
|
-
out = pattern.sub(
|
|
79
|
+
for pattern, replacement in TOKEN_PATTERNS:
|
|
80
|
+
out = pattern.sub(
|
|
81
|
+
lambda match: match.group(0).replace(match.group(2), replacement)
|
|
82
|
+
if len(match.groups()) >= 2
|
|
83
|
+
else replacement,
|
|
84
|
+
out,
|
|
85
|
+
)
|
|
54
86
|
return out
|
|
55
87
|
|
|
56
88
|
|
|
@@ -289,7 +321,7 @@ def main() -> int:
|
|
|
289
321
|
for reply in replies:
|
|
290
322
|
lines.extend(render_message(reply))
|
|
291
323
|
|
|
292
|
-
source_path.write_text("\n".join(lines), encoding="utf-8")
|
|
324
|
+
source_path.write_text(redact("\n".join(lines)), encoding="utf-8")
|
|
293
325
|
|
|
294
326
|
latest_ts = previous_state.get("latest_message_ts")
|
|
295
327
|
if messages:
|