@codyswann/lisa 2.142.3 → 2.143.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.
- 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/commands/repair-intake.md +2 -2
- package/plugins/lisa/skills/repair-intake/SKILL.md +64 -9
- package/plugins/lisa-agy/commands/repair-intake.md +2 -2
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/repair-intake/SKILL.md +64 -9
- 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/commands/repair-intake.md +2 -2
- package/plugins/lisa-copilot/skills/repair-intake/SKILL.md +64 -9
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/commands/repair-intake.md +2 -2
- package/plugins/lisa-cursor/skills/repair-intake/SKILL.md +64 -9
- 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-safety.mjs +199 -0
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/scripts/wiki-safety.mjs +199 -0
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/scripts/wiki-safety.mjs +199 -0
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/scripts/wiki-safety.mjs +199 -0
- package/plugins/src/base/commands/repair-intake.md +2 -2
- package/plugins/src/base/skills/repair-intake/SKILL.md +64 -9
- package/plugins/src/wiki/scripts/wiki-safety.mjs +199 -0
|
@@ -49,6 +49,11 @@ close-out** roles and moves work *unstuck* or *fully closed*:
|
|
|
49
49
|
lifecycle label. repair-intake classifies it as a PRD or build ticket and adds the configured
|
|
50
50
|
`ready` label (`prd-ready` for a PRD, build `status:ready` for a ticket) so normal intake can see
|
|
51
51
|
it; if the later intake/implement gate finds the item incomplete, it moves the item to `blocked`.
|
|
52
|
+
- **Missing PRD child link drift** — a GitHub PRD in `ticketed` (or another open non-product-owned
|
|
53
|
+
PRD role) has a generated-work section/comment that names top-level generated work, but the PRD's
|
|
54
|
+
native sub-issue list is missing one or more of those top-level children. repair-intake replays the
|
|
55
|
+
`prd-backlink` native-linking contract and attaches the missing same-repo top-level children
|
|
56
|
+
idempotently, so PRD rollup can rely on the native graph again.
|
|
52
57
|
|
|
53
58
|
This skill is the symmetric counterpart to `lisa:intake`. It reuses the same queue-detection,
|
|
54
59
|
the same agent-team orchestration, the same "don't ask, just run" confirmation policy, and the
|
|
@@ -152,7 +157,7 @@ claim-and-advance). The essentials, inlined here so this skill is self-complete:
|
|
|
152
157
|
| Confluence **space** URL/key | PRD (Confluence) | source=confluence | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
|
|
153
158
|
| Confluence **parent page** URL/ID | PRD (Confluence, narrowed) | source=confluence | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
|
|
154
159
|
| Linear **workspace** URL, **team** URL/key, or literal `linear` | PRD (Linear) | source=linear | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
|
|
155
|
-
| GitHub **repo** URL / `org/repo` (PRD namespace) | PRD (GitHub) | source=github | `in_review`, `blocked`, terminal/open PRDs, all-terminal generated-work rollups |
|
|
160
|
+
| GitHub **repo** URL / `org/repo` (PRD namespace) | PRD (GitHub) | source=github | `in_review`, `blocked`, terminal/open PRDs, missing PRD child links, all-terminal generated-work rollups |
|
|
156
161
|
| GitHub **repo** URL / `org/repo` with `tracker = github` (build namespace) | Build (GitHub) | tracker=github | `claimed`, `blocked`, terminal/open issues, parent rollups (intermediate-env + all-terminal), stale-`ready` containers |
|
|
157
162
|
| GitHub **repo** URL / `org/repo` with an open issue missing configured lifecycle labels | GitHub label normalization | per classified lifecycle | add configured `prd.ready` or build `ready` |
|
|
158
163
|
| Literal `github` | GitHub; route by `intake_mode` (`prd` / `build` / `both`) | per lifecycle | per lifecycle above, plus GitHub ready-label normalization |
|
|
@@ -550,6 +555,47 @@ work is fully terminal:
|
|
|
550
555
|
5. If generated work is missing, ambiguous, or partially incomplete, leave the PRD open and report
|
|
551
556
|
the incomplete child set. Never close a PRD on partial completion.
|
|
552
557
|
|
|
558
|
+
### GitHub PRD missing child links → native sub-issue repair
|
|
559
|
+
|
|
560
|
+
For each open GitHub PRD in `ticketed` or another non-product-owned PRD role, compare the durable
|
|
561
|
+
generated-work fallback against the PRD's native sub-issue graph and repair missing native links.
|
|
562
|
+
This is the recovery counterpart to `lisa:prd-backlink`'s GitHub native parent-linking section:
|
|
563
|
+
PRD intake/backlink should attach generated top-level work as native PRD children when possible,
|
|
564
|
+
but repair-intake must heal the graph when that write was skipped, failed, or later drifted.
|
|
565
|
+
|
|
566
|
+
1. Read the generated work exactly as PRD rollup does:
|
|
567
|
+
- Prefer the machine-readable `## Tickets` / `## Generated Work` section (`lisa:gw` tokens).
|
|
568
|
+
- If the machine-readable section is absent but an older Lisa ticketing comment exists, parse only
|
|
569
|
+
its structured `Top-level work:` block as a compatibility fallback. Do not scrape arbitrary
|
|
570
|
+
prose.
|
|
571
|
+
2. Select only generated **top-level** work:
|
|
572
|
+
- `lisa:gw` entries whose `parent` token is empty.
|
|
573
|
+
- Older ticketing-comment entries under `Top-level work:`.
|
|
574
|
+
Leaf Sub-tasks and descendant Stories are never direct PRD children.
|
|
575
|
+
3. Restrict native repair to same-repo GitHub issues. Cross-repo or cross-vendor generated work stays
|
|
576
|
+
documented-only; record a warning instead of failing.
|
|
577
|
+
4. Read the PRD's existing native sub-issues with the same GraphQL `subIssues` query documented by
|
|
578
|
+
`lisa:prd-backlink` / `lisa:github-read-issue`, and dedupe by child-ref
|
|
579
|
+
(`owner/repo#number`).
|
|
580
|
+
5. For each missing same-repo top-level child, resolve node IDs and call the same GitHub GraphQL
|
|
581
|
+
mutation as `prd-backlink`:
|
|
582
|
+
|
|
583
|
+
```graphql
|
|
584
|
+
mutation($parentId:ID!,$childId:ID!){
|
|
585
|
+
addSubIssue(input:{issueId:$parentId,subIssueId:$childId}){issue{number}subIssue{number}}
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
Treat "already linked" duplicate rejections as success. If `subIssues` / `addSubIssue` is
|
|
590
|
+
unavailable, leave the documented generated-work fallback intact, record a capability warning, and
|
|
591
|
+
continue.
|
|
592
|
+
6. Post one idempotent `[lisa-repair-intake]` note when a missing native PRD child link is repaired
|
|
593
|
+
or when the native-link capability is unavailable. Include the generated top-level child set, the
|
|
594
|
+
pre-existing native child set, and repaired child refs in the state fingerprint so repeated cycles
|
|
595
|
+
do not spam comments.
|
|
596
|
+
7. Do not transition the PRD lifecycle merely because child links were repaired. Rollup/ship remains
|
|
597
|
+
governed by the PRD rollup path after the child graph is complete.
|
|
598
|
+
|
|
553
599
|
### GitHub missing official ready-label normalization → configured ready
|
|
554
600
|
|
|
555
601
|
For GitHub queues, enumerate open issues that have **no configured Lisa lifecycle label** in the
|
|
@@ -708,6 +754,9 @@ It MAY:
|
|
|
708
754
|
applies only to containers, never to leaves.
|
|
709
755
|
- Move a PRD with fully terminal generated work to `shipped` and close/archive the source artifact
|
|
710
756
|
where the source vendor supports native close-out, per `prd-lifecycle-rollup`.
|
|
757
|
+
- Repair missing native GitHub PRD child links from the generated-work fallback by replaying the
|
|
758
|
+
`prd-backlink` top-level-only, same-repo, idempotent `addSubIssue` contract. This repairs
|
|
759
|
+
structure only; it does not ship or verify the PRD.
|
|
711
760
|
- Normalize a GitHub issue with no configured lifecycle label by adding the configured PRD or build
|
|
712
761
|
`ready` label after classifying the issue. This is a visibility repair, not a claim; the item
|
|
713
762
|
remains open and unclaimed for normal intake.
|
|
@@ -715,6 +764,8 @@ It MAY:
|
|
|
715
764
|
It MUST NOT:
|
|
716
765
|
|
|
717
766
|
- Move a PRD out of `draft` or `verified` (those are product-owned), or set `verified` itself.
|
|
767
|
+
- Link leaf Sub-tasks or descendant Stories directly under a PRD. Only generated top-level work
|
|
768
|
+
(empty parent token / `Top-level work:` entries) may become PRD children.
|
|
718
769
|
- Apply a build `done` value other than via the env-resolution rules, or close a native item at
|
|
719
770
|
any value other than the true terminal `done` (see `leaf-only-lifecycle`).
|
|
720
771
|
- Touch `ready` **leaves** (that is `lisa:intake`'s lane). A container carrying `ready` is the
|
|
@@ -728,21 +779,23 @@ It MUST NOT:
|
|
|
728
779
|
1. **Resolve the queue** — detect vendor/lifecycle (Source dispatch); resolve stuck role names
|
|
729
780
|
from config. For JIRA, confirm the needed transitions are reachable; stop on misconfig.
|
|
730
781
|
2. **Enumerate repair candidates** — query in-progress role(s), `blocked` role(s), terminal/open
|
|
731
|
-
items,
|
|
782
|
+
items, GitHub PRDs whose generated-work fallback names top-level children missing from native
|
|
783
|
+
sub-issues, rollup parents/PRDs with child work, **containers carrying the `ready` role** (a
|
|
732
784
|
leaf-only-invariant violation to reconcile), and GitHub issues with no configured lifecycle label,
|
|
733
785
|
for the detected lifecycle(s), up to `max_candidates`, via the Access layer reads.
|
|
734
786
|
3. **Order deterministically**, highest repair-confidence first:
|
|
735
787
|
1. terminal-labeled items that only need native close / complete / resolve,
|
|
736
|
-
2.
|
|
737
|
-
3. rollup parents whose
|
|
788
|
+
2. GitHub PRDs missing native links for generated top-level work (structure-only repair),
|
|
789
|
+
3. rollup parents/PRDs whose child sets are all terminal (close-out),
|
|
790
|
+
4. rollup parents whose children have advanced to an intermediate env, or stale-`ready`
|
|
738
791
|
containers, that need their derived state applied (status-only reconciliation, no native
|
|
739
792
|
close),
|
|
740
|
-
|
|
741
|
-
|
|
793
|
+
5. `blocked` items whose dependencies are now **cleared** (safe, high-value, one-cycle wins),
|
|
794
|
+
6. `blocked` items whose **validation / quality-gate self-block now re-validates PASS** —
|
|
742
795
|
a human filled in the missing sections (Class B; equally safe and high-value),
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
796
|
+
7. `blocked` items with **new clarifying answers**,
|
|
797
|
+
8. GitHub missing-official-label normalization candidates,
|
|
798
|
+
9. **stalled** in-progress items, oldest activity first.
|
|
746
799
|
4. **Walk the ordered list**, evaluating each candidate (terminal close-out, rollup child tally,
|
|
747
800
|
staleness, dependency, answer checks), and repair **every** candidate that is actionable inside
|
|
748
801
|
the `max_candidates` cap. Continue after successful writes and after per-item errors.
|
|
@@ -773,6 +826,8 @@ Report outcomes in these buckets:
|
|
|
773
826
|
- `rolled_up` — parent/container/PRD rollups advanced to their derived state: an intermediate env
|
|
774
827
|
(e.g. all children at `On Stg` → parent `On Stg`), a fully-terminal close-out, or a stale-`ready`
|
|
775
828
|
container reconciled from its children.
|
|
829
|
+
- `relinked` — GitHub PRDs whose missing native sub-issue links were repaired from the
|
|
830
|
+
generated-work fallback.
|
|
776
831
|
- `normalized_ready` — GitHub issues missing official lifecycle labels that were classified and
|
|
777
832
|
given the configured PRD/build `ready` label so normal intake can claim them.
|
|
778
833
|
- `still_blocked` — examined and intentionally left `blocked`, with the active reason.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.143.1",
|
|
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.143.1",
|
|
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.143.1",
|
|
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.143.1",
|
|
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.143.1",
|
|
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"
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic wiki source safety helpers.
|
|
4
|
+
*
|
|
5
|
+
* This module intentionally uses only Node built-ins and pure string scanning so
|
|
6
|
+
* downstream wiki connectors can run the same redaction pass before persisting
|
|
7
|
+
* reader-safe source notes.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const PLACEHOLDERS = {
|
|
11
|
+
ssn: "[REDACTED:SSN]",
|
|
12
|
+
credit_card: "[REDACTED:CREDIT_CARD]",
|
|
13
|
+
private_key: "[REDACTED:PRIVATE_KEY]",
|
|
14
|
+
password: "[REDACTED:PASSWORD]",
|
|
15
|
+
api_key: "[REDACTED:API_KEY]",
|
|
16
|
+
oauth_token: "[REDACTED:OAUTH_TOKEN]",
|
|
17
|
+
bank_account: "[REDACTED:BANK_ACCOUNT]",
|
|
18
|
+
routing_number: "[REDACTED:ROUTING_NUMBER]",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const PATTERNS = [
|
|
22
|
+
{
|
|
23
|
+
entityType: "private_key",
|
|
24
|
+
confidence: "high",
|
|
25
|
+
re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/g,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
entityType: "ssn",
|
|
29
|
+
confidence: "high",
|
|
30
|
+
re: /\b(?!000|666|9\d\d)\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b/g,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
entityType: "password",
|
|
34
|
+
confidence: "high",
|
|
35
|
+
re: /\b(?:password|passwd|pwd)\s*[:=]\s*(['"]?)([^\s'",;]{8,})\1/gi,
|
|
36
|
+
valueGroup: 2,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
entityType: "api_key",
|
|
40
|
+
confidence: "medium",
|
|
41
|
+
re: /\b(?:api[_-]?key|access[_-]?key|secret[_-]?key|client[_-]?secret)\s*[:=]\s*(['"]?)([A-Za-z0-9._-]{20,})\1/gi,
|
|
42
|
+
valueGroup: 2,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
entityType: "oauth_token",
|
|
46
|
+
confidence: "high",
|
|
47
|
+
re: /\b(?:oauth[_-]?token|refresh[_-]?token|access[_-]?token|bearer)\s*[:= ]\s*(['"]?)([A-Za-z0-9._-]{24,})\1/gi,
|
|
48
|
+
valueGroup: 2,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
entityType: "routing_number",
|
|
52
|
+
confidence: "medium",
|
|
53
|
+
re: /\b(?:routing|routing_number|aba)\s*(?:number|no\.?)?\s*[:#=]?\s*(\d{9})\b/gi,
|
|
54
|
+
valueGroup: 1,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
entityType: "bank_account",
|
|
58
|
+
confidence: "medium",
|
|
59
|
+
re: /\b(?:bank\s+)?(?:account|acct)\s*(?:number|no\.?)?\s*[:#=]?\s*(\d{6,17})\b/gi,
|
|
60
|
+
valueGroup: 1,
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
function luhnValid(candidate) {
|
|
65
|
+
const digits = candidate.replace(/\D/g, "");
|
|
66
|
+
if (digits.length < 13 || digits.length > 19) return false;
|
|
67
|
+
let sum = 0;
|
|
68
|
+
let doubleDigit = false;
|
|
69
|
+
for (let i = digits.length - 1; i >= 0; i -= 1) {
|
|
70
|
+
let n = Number(digits[i]);
|
|
71
|
+
if (doubleDigit) {
|
|
72
|
+
n *= 2;
|
|
73
|
+
if (n > 9) n -= 9;
|
|
74
|
+
}
|
|
75
|
+
sum += n;
|
|
76
|
+
doubleDigit = !doubleDigit;
|
|
77
|
+
}
|
|
78
|
+
return sum % 10 === 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function applyFinding(text, match, pattern) {
|
|
82
|
+
const raw = match[0];
|
|
83
|
+
const value = pattern.valueGroup ? match[pattern.valueGroup] : raw;
|
|
84
|
+
const valueOffset = pattern.valueGroup ? raw.indexOf(value) : 0;
|
|
85
|
+
const start = match.index + valueOffset;
|
|
86
|
+
const end = start + value.length;
|
|
87
|
+
return {
|
|
88
|
+
sanitized:
|
|
89
|
+
text.slice(0, start) + PLACEHOLDERS[pattern.entityType] + text.slice(end),
|
|
90
|
+
finding: {
|
|
91
|
+
entityType: pattern.entityType,
|
|
92
|
+
confidence: pattern.confidence,
|
|
93
|
+
range: { start, end },
|
|
94
|
+
},
|
|
95
|
+
delta: PLACEHOLDERS[pattern.entityType].length - value.length,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function collectCreditCardFindings(text) {
|
|
100
|
+
const findings = [];
|
|
101
|
+
const re = /\b(?:\d[ -]?){13,19}\b/g;
|
|
102
|
+
let match;
|
|
103
|
+
while ((match = re.exec(text)) !== null) {
|
|
104
|
+
const value = match[0].trim();
|
|
105
|
+
if (!luhnValid(value)) continue;
|
|
106
|
+
findings.push({
|
|
107
|
+
entityType: "credit_card",
|
|
108
|
+
confidence: "high",
|
|
109
|
+
range: { start: match.index, end: match.index + match[0].length },
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return findings;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function summarizeFindings(sourceMetadata, findings) {
|
|
116
|
+
const sourceId =
|
|
117
|
+
sourceMetadata.sourceId ??
|
|
118
|
+
sourceMetadata.id ??
|
|
119
|
+
sourceMetadata.path ??
|
|
120
|
+
sourceMetadata.url ??
|
|
121
|
+
"unknown";
|
|
122
|
+
const byType = new Map();
|
|
123
|
+
for (const finding of findings) {
|
|
124
|
+
const current = byType.get(finding.entityType) ?? {
|
|
125
|
+
sourceId,
|
|
126
|
+
entityType: finding.entityType,
|
|
127
|
+
confidence: finding.confidence,
|
|
128
|
+
count: 0,
|
|
129
|
+
ranges: [],
|
|
130
|
+
};
|
|
131
|
+
current.count += 1;
|
|
132
|
+
current.ranges.push(finding.range);
|
|
133
|
+
byType.set(finding.entityType, current);
|
|
134
|
+
}
|
|
135
|
+
return [...byType.values()].sort((a, b) =>
|
|
136
|
+
a.entityType.localeCompare(b.entityType)
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function collectFindings(rawText) {
|
|
141
|
+
const text = String(rawText ?? "");
|
|
142
|
+
const findings = [];
|
|
143
|
+
|
|
144
|
+
for (const pattern of PATTERNS) {
|
|
145
|
+
pattern.re.lastIndex = 0;
|
|
146
|
+
let match;
|
|
147
|
+
while ((match = pattern.re.exec(text)) !== null) {
|
|
148
|
+
findings.push(applyFinding(text, match, pattern).finding);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
findings.push(...collectCreditCardFindings(text));
|
|
152
|
+
findings.sort((a, b) => a.range.start - b.range.start);
|
|
153
|
+
return findings;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function scanWikiSourceText(rawText, sourceMetadata = {}) {
|
|
157
|
+
const findings = collectFindings(rawText);
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
sourceId:
|
|
161
|
+
sourceMetadata.sourceId ??
|
|
162
|
+
sourceMetadata.id ??
|
|
163
|
+
sourceMetadata.path ??
|
|
164
|
+
sourceMetadata.url ??
|
|
165
|
+
"unknown",
|
|
166
|
+
reviewRequired: findings.length > 0,
|
|
167
|
+
findings: summarizeFindings(sourceMetadata, findings),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function sanitizeWikiSourceText(rawText, sourceMetadata = {}) {
|
|
172
|
+
let sanitized = String(rawText ?? "");
|
|
173
|
+
const rawFindings = collectFindings(rawText);
|
|
174
|
+
for (const finding of [...rawFindings].sort(
|
|
175
|
+
(a, b) => b.range.start - a.range.start
|
|
176
|
+
)) {
|
|
177
|
+
sanitized =
|
|
178
|
+
sanitized.slice(0, finding.range.start) +
|
|
179
|
+
PLACEHOLDERS[finding.entityType] +
|
|
180
|
+
sanitized.slice(finding.range.end);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
text: sanitized,
|
|
185
|
+
reviewRequired: rawFindings.length > 0,
|
|
186
|
+
findings: summarizeFindings(sourceMetadata, rawFindings),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function serializeWikiSafetyFindings(result) {
|
|
191
|
+
return JSON.stringify(
|
|
192
|
+
{
|
|
193
|
+
reviewRequired: Boolean(result?.reviewRequired),
|
|
194
|
+
findings: Array.isArray(result?.findings) ? result.findings : [],
|
|
195
|
+
},
|
|
196
|
+
null,
|
|
197
|
+
2
|
|
198
|
+
);
|
|
199
|
+
}
|