@codyswann/lisa 2.196.0 → 2.197.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-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/scripts/lisa-github-repo-setup.sh +11 -1
- package/scripts/lisa-github-rulesets.sh +123 -17
- package/scripts/setup-deploy-key.sh +5 -4
- package/cdk/github-rulesets/cdk-validation.json +0 -43
package/package.json
CHANGED
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"ws": ">=8.20.1"
|
|
95
95
|
},
|
|
96
96
|
"name": "@codyswann/lisa",
|
|
97
|
-
"version": "2.
|
|
97
|
+
"version": "2.197.0",
|
|
98
98
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
99
99
|
"main": "dist/index.js",
|
|
100
100
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.197.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.197.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.197.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.197.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.197.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"
|
|
@@ -56,7 +56,17 @@ echo "==> Step 3/3: deploy key"
|
|
|
56
56
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
57
57
|
echo "[DRY RUN] Would ensure a write-access deploy key + DEPLOY_KEY secret exist"
|
|
58
58
|
else
|
|
59
|
-
(cd "$PROJECT_PATH" && bash "$SCRIPT_DIR/setup-deploy-key.sh" --yes)
|
|
59
|
+
deploy_output=$(cd "$PROJECT_PATH" && bash "$SCRIPT_DIR/setup-deploy-key.sh" --yes 2>&1)
|
|
60
|
+
deploy_rc=$?
|
|
61
|
+
echo "$deploy_output"
|
|
62
|
+
if [[ $deploy_rc -ne 0 ]]; then
|
|
63
|
+
if echo "$deploy_output" | grep -qi "deploy keys are disabled"; then
|
|
64
|
+
# Org policy, not a repo problem — settings/rulesets still applied.
|
|
65
|
+
echo "⚠ Deploy keys are disabled by organization policy — skipped. Release workflows needing DEPLOY_KEY will not work until an org admin re-enables deploy keys."
|
|
66
|
+
else
|
|
67
|
+
exit $deploy_rc
|
|
68
|
+
fi
|
|
69
|
+
fi
|
|
60
70
|
fi
|
|
61
71
|
|
|
62
72
|
echo ""
|
|
@@ -309,6 +309,48 @@ strip_actions_checks_if_no_workflows() {
|
|
|
309
309
|
else . end'
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
# Per-repo opt-out: .lisa.config.json can list required-check contexts that
|
|
313
|
+
# must never be required on this repository, e.g. wikis that should not gate
|
|
314
|
+
# on CodeRabbit:
|
|
315
|
+
# { "github": { "rulesets": { "dropRequiredChecks": ["CodeRabbit"] } } }
|
|
316
|
+
strip_config_dropped_checks() {
|
|
317
|
+
local json="$1"
|
|
318
|
+
local project_path="$2"
|
|
319
|
+
local config="$project_path/.lisa.config.json"
|
|
320
|
+
|
|
321
|
+
if [[ ! -f "$config" ]]; then
|
|
322
|
+
echo "$json"
|
|
323
|
+
return 0
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
local dropped
|
|
327
|
+
if ! dropped=$(jq -c '.github.rulesets.dropRequiredChecks // []' "$config" 2>/dev/null); then
|
|
328
|
+
log_warning ".lisa.config.json could not be parsed — ignoring github.rulesets overrides" >&2
|
|
329
|
+
dropped="[]"
|
|
330
|
+
fi
|
|
331
|
+
|
|
332
|
+
if [[ "$dropped" == "[]" ]]; then
|
|
333
|
+
echo "$json"
|
|
334
|
+
return 0
|
|
335
|
+
fi
|
|
336
|
+
|
|
337
|
+
echo "$json" | jq --argjson dropped "$dropped" '
|
|
338
|
+
if .rules then
|
|
339
|
+
.rules |= (
|
|
340
|
+
map(
|
|
341
|
+
if .type == "required_status_checks" then
|
|
342
|
+
.parameters.required_status_checks |=
|
|
343
|
+
map(select(.context as $c | ($dropped | index($c)) | not))
|
|
344
|
+
else . end
|
|
345
|
+
)
|
|
346
|
+
| map(select(
|
|
347
|
+
.type != "required_status_checks"
|
|
348
|
+
or (.parameters.required_status_checks | length) > 0
|
|
349
|
+
))
|
|
350
|
+
)
|
|
351
|
+
else . end'
|
|
352
|
+
}
|
|
353
|
+
|
|
312
354
|
apply_ruleset() {
|
|
313
355
|
local repo="$1"
|
|
314
356
|
local template_file="$2"
|
|
@@ -324,6 +366,7 @@ apply_ruleset() {
|
|
|
324
366
|
local clean_template
|
|
325
367
|
clean_template=$(strip_readonly_fields "$template_content")
|
|
326
368
|
clean_template=$(strip_actions_checks_if_no_workflows "$clean_template" "$project_path")
|
|
369
|
+
clean_template=$(strip_config_dropped_checks "$clean_template" "$project_path")
|
|
327
370
|
|
|
328
371
|
# A template whose rules were entirely stripped has nothing to enforce here.
|
|
329
372
|
if [[ $(echo "$clean_template" | jq '(.rules // [1]) | length') -eq 0 ]]; then
|
|
@@ -344,32 +387,95 @@ apply_ruleset() {
|
|
|
344
387
|
return 0
|
|
345
388
|
fi
|
|
346
389
|
|
|
347
|
-
# Create temp file for the request body
|
|
348
|
-
local temp_file
|
|
349
|
-
temp_file=$(mktemp)
|
|
350
|
-
echo "$clean_template" > "$temp_file"
|
|
351
|
-
|
|
352
390
|
if [[ -n "$existing_id" ]]; then
|
|
353
391
|
log_info "Updating ruleset '$ruleset_name' (id: $existing_id)..."
|
|
354
|
-
if gh api -X PUT "repos/$repo/rulesets/$existing_id" --input "$temp_file" > /dev/null; then
|
|
355
|
-
log_success "Updated ruleset '$ruleset_name'"
|
|
356
|
-
else
|
|
357
|
-
log_error "Failed to update ruleset '$ruleset_name'"
|
|
358
|
-
rm -f "$temp_file"
|
|
359
|
-
return 1
|
|
360
|
-
fi
|
|
361
392
|
else
|
|
362
393
|
log_info "Creating ruleset '$ruleset_name'..."
|
|
363
|
-
|
|
364
|
-
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
if apply_with_integration_fallback "$repo" "$ruleset_name" "$clean_template" "$existing_id"; then
|
|
397
|
+
return 0
|
|
398
|
+
fi
|
|
399
|
+
log_error "Failed to apply ruleset '$ruleset_name'"
|
|
400
|
+
return 1
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
# Send the ruleset to GitHub. App-based required checks (CodeRabbit,
|
|
404
|
+
# GitGuardian, ...) are rejected with "Invalid integration ids" on repos
|
|
405
|
+
# where that app is not installed — and no user-token API can list per-repo
|
|
406
|
+
# installations up front. So on that specific error, retry with app-based
|
|
407
|
+
# checks progressively removed: first each single app id, then all of them,
|
|
408
|
+
# keeping as many checks as the repo actually supports.
|
|
409
|
+
apply_with_integration_fallback() {
|
|
410
|
+
local repo="$1"
|
|
411
|
+
local ruleset_name="$2"
|
|
412
|
+
local payload="$3"
|
|
413
|
+
local existing_id="$4"
|
|
414
|
+
|
|
415
|
+
local temp_file error_output
|
|
416
|
+
temp_file=$(mktemp)
|
|
417
|
+
|
|
418
|
+
# Capture stdout AND stderr — gh prints the API error body (which carries
|
|
419
|
+
# the "Invalid integration ids" detail) on stdout, not stderr.
|
|
420
|
+
send_ruleset() {
|
|
421
|
+
echo "$1" > "$temp_file"
|
|
422
|
+
if [[ -n "$existing_id" ]]; then
|
|
423
|
+
error_output=$(gh api -X PUT "repos/$repo/rulesets/$existing_id" --input "$temp_file" 2>&1)
|
|
365
424
|
else
|
|
366
|
-
|
|
367
|
-
rm -f "$temp_file"
|
|
368
|
-
return 1
|
|
425
|
+
error_output=$(gh api -X POST "repos/$repo/rulesets" --input "$temp_file" 2>&1)
|
|
369
426
|
fi
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if send_ruleset "$payload"; then
|
|
430
|
+
log_success "Applied ruleset '$ruleset_name'"
|
|
431
|
+
rm -f "$temp_file"
|
|
432
|
+
return 0
|
|
370
433
|
fi
|
|
371
434
|
|
|
435
|
+
if ! echo "$error_output" | grep -qi "invalid integration ids"; then
|
|
436
|
+
log_error "$error_output"
|
|
437
|
+
rm -f "$temp_file"
|
|
438
|
+
return 1
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
local app_ids
|
|
442
|
+
app_ids=$(echo "$payload" | jq --argjson actions "$ACTIONS_INTEGRATION_ID" \
|
|
443
|
+
'[.rules[]? | select(.type=="required_status_checks") | .parameters.required_status_checks[]?.integration_id | select(. != null and . != $actions)] | unique | .[]')
|
|
444
|
+
|
|
445
|
+
local drop_filter='
|
|
446
|
+
.rules |= (
|
|
447
|
+
map(
|
|
448
|
+
if .type == "required_status_checks" then
|
|
449
|
+
.parameters.required_status_checks |= map(select((.integration_id // -1) as $i | ($drop | index($i)) | not))
|
|
450
|
+
else . end
|
|
451
|
+
)
|
|
452
|
+
| map(select(.type != "required_status_checks" or (.parameters.required_status_checks | length) > 0))
|
|
453
|
+
)'
|
|
454
|
+
|
|
455
|
+
# Each single app id first (keep the most checks), then all app ids.
|
|
456
|
+
local candidates=()
|
|
457
|
+
local app_id
|
|
458
|
+
for app_id in $app_ids; do
|
|
459
|
+
candidates+=("[$app_id]")
|
|
460
|
+
done
|
|
461
|
+
candidates+=("$(echo "$app_ids" | jq -s -c .)")
|
|
462
|
+
|
|
463
|
+
local drop attempt
|
|
464
|
+
for drop in "${candidates[@]}"; do
|
|
465
|
+
attempt=$(echo "$payload" | jq --argjson drop "$drop" --argjson actions "$ACTIONS_INTEGRATION_ID" "$drop_filter")
|
|
466
|
+
if [[ $(echo "$attempt" | jq '(.rules // [1]) | length') -eq 0 ]]; then
|
|
467
|
+
continue
|
|
468
|
+
fi
|
|
469
|
+
if send_ruleset "$attempt"; then
|
|
470
|
+
log_warning "Applied ruleset '$ruleset_name' without app integration id(s) $drop — app(s) not installed on this repository"
|
|
471
|
+
rm -f "$temp_file"
|
|
472
|
+
return 0
|
|
473
|
+
fi
|
|
474
|
+
done
|
|
475
|
+
|
|
476
|
+
log_error "$error_output"
|
|
372
477
|
rm -f "$temp_file"
|
|
478
|
+
return 1
|
|
373
479
|
}
|
|
374
480
|
|
|
375
481
|
##############################################################################
|
|
@@ -89,8 +89,9 @@ if [[ "$YES_MODE" == "true" ]]; then
|
|
|
89
89
|
exit 1
|
|
90
90
|
fi
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
# NOTE: gh's --jq flag does not support jq --arg; pipe through jq instead.
|
|
93
|
+
HAS_KEY=$(gh repo deploy-key list --repo "$OWNER/$REPO" --json title 2>/dev/null \
|
|
94
|
+
| jq --arg t "$KEY_TITLE" '[.[] | select(.title == $t)] | length' 2>/dev/null || echo 0)
|
|
94
95
|
HAS_SECRET=$(gh secret list --repo "$OWNER/$REPO" --json name \
|
|
95
96
|
--jq '[.[] | select(.name == "DEPLOY_KEY")] | length' 2>/dev/null || echo 0)
|
|
96
97
|
if [[ "$HAS_KEY" -gt 0 && "$HAS_SECRET" -gt 0 ]]; then
|
|
@@ -107,8 +108,8 @@ if [[ "$YES_MODE" == "true" ]]; then
|
|
|
107
108
|
|
|
108
109
|
# A stale key under the same title blocks re-adding; replace it.
|
|
109
110
|
if [[ "$HAS_KEY" -gt 0 ]]; then
|
|
110
|
-
gh repo deploy-key list --repo "$OWNER/$REPO" --json id,title \
|
|
111
|
-
|
|
111
|
+
gh repo deploy-key list --repo "$OWNER/$REPO" --json id,title 2>/dev/null \
|
|
112
|
+
| jq -r --arg t "$KEY_TITLE" '.[] | select(.title == $t) | .id' \
|
|
112
113
|
| while read -r key_id; do
|
|
113
114
|
gh repo deploy-key delete "$key_id" --repo "$OWNER/$REPO" || true
|
|
114
115
|
done
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cdk validation",
|
|
3
|
-
"target": "branch",
|
|
4
|
-
"enforcement": "active",
|
|
5
|
-
"conditions": {
|
|
6
|
-
"ref_name": {
|
|
7
|
-
"exclude": [],
|
|
8
|
-
"include": [
|
|
9
|
-
"~DEFAULT_BRANCH",
|
|
10
|
-
"refs/heads/dev",
|
|
11
|
-
"refs/heads/staging",
|
|
12
|
-
"refs/heads/main"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"bypass_actors": [
|
|
17
|
-
{
|
|
18
|
-
"actor_id": null,
|
|
19
|
-
"actor_type": "DeployKey",
|
|
20
|
-
"bypass_mode": "always"
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"actor_id": 5,
|
|
24
|
-
"actor_type": "RepositoryRole",
|
|
25
|
-
"bypass_mode": "always"
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
"rules": [
|
|
29
|
-
{
|
|
30
|
-
"type": "required_status_checks",
|
|
31
|
-
"parameters": {
|
|
32
|
-
"strict_required_status_checks_policy": false,
|
|
33
|
-
"do_not_enforce_on_create": true,
|
|
34
|
-
"required_status_checks": [
|
|
35
|
-
{
|
|
36
|
-
"context": "🏗️ CDK Validation",
|
|
37
|
-
"integration_id": 15368
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}
|