@codyswann/lisa 2.191.14 → 2.192.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/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
- package/dist/configs/eslint/harper-fabric.js +5 -0
- package/dist/configs/eslint/harper-fabric.js.map +1 -1
- package/harper-fabric/copy-contents/.prettierignore +1 -0
- package/harper-fabric/copy-contents/gitignore +7 -0
- package/harper-fabric/copy-overwrite/.github/dependabot.yml +47 -0
- package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-early-return-in-search-loop.yml +27 -0
- package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-empty-conditions-with-sort.yml +45 -0
- package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-full-table-scan.yml +33 -0
- package/harper-fabric/copy-overwrite/ast-grep/rules/harper/require-statuscode-on-thrown-error.yml +41 -0
- package/harper-fabric/copy-overwrite/knip.json +1 -0
- package/harper-fabric/copy-overwrite/tsconfig.eslint.json +1 -0
- package/harper-fabric/merge/.oxlintrc.json +1 -0
- package/oxlint/harper-fabric.json +1 -0
- 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/generated-artifact-globs.txt +1 -0
- package/plugins/lisa-harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
- package/plugins/lisa-harper-fabric/rules/harper-fabric.md +1 -1
- package/plugins/lisa-harper-fabric/skills/harper-auth/SKILL.md +48 -0
- package/plugins/lisa-harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
- package/plugins/lisa-harper-fabric/skills/harper-resources/SKILL.md +35 -0
- package/plugins/lisa-harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
- package/plugins/lisa-harper-fabric-agy/generated-artifact-globs.txt +1 -0
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/skills/harper-auth/SKILL.md +48 -0
- package/plugins/lisa-harper-fabric-agy/skills/harper-build-and-deploy/SKILL.md +20 -5
- package/plugins/lisa-harper-fabric-agy/skills/harper-resources/SKILL.md +35 -0
- package/plugins/lisa-harper-fabric-agy/skills/harper-rest-queries/SKILL.md +40 -3
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/generated-artifact-globs.txt +1 -0
- package/plugins/lisa-harper-fabric-copilot/hooks/block-generated-artifact-edits.sh +51 -0
- package/plugins/lisa-harper-fabric-copilot/rules/harper-fabric.md +1 -1
- package/plugins/lisa-harper-fabric-copilot/skills/harper-auth/SKILL.md +48 -0
- package/plugins/lisa-harper-fabric-copilot/skills/harper-build-and-deploy/SKILL.md +20 -5
- package/plugins/lisa-harper-fabric-copilot/skills/harper-resources/SKILL.md +35 -0
- package/plugins/lisa-harper-fabric-copilot/skills/harper-rest-queries/SKILL.md +40 -3
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/generated-artifact-globs.txt +1 -0
- package/plugins/lisa-harper-fabric-cursor/hooks/block-generated-artifact-edits.sh +51 -0
- package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +1 -1
- package/plugins/lisa-harper-fabric-cursor/skills/harper-auth/SKILL.md +48 -0
- package/plugins/lisa-harper-fabric-cursor/skills/harper-build-and-deploy/SKILL.md +20 -5
- package/plugins/lisa-harper-fabric-cursor/skills/harper-resources/SKILL.md +35 -0
- package/plugins/lisa-harper-fabric-cursor/skills/harper-rest-queries/SKILL.md +40 -3
- 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/harper-fabric/generated-artifact-globs.txt +1 -0
- package/plugins/src/harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
- package/plugins/src/harper-fabric/rules/harper-fabric.md +1 -1
- package/plugins/src/harper-fabric/skills/harper-auth/SKILL.md +48 -0
- package/plugins/src/harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
- package/plugins/src/harper-fabric/skills/harper-resources/SKILL.md +35 -0
- package/plugins/src/harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harper-fabric.d.ts","sourceRoot":"","sources":["../../../src/configs/eslint/harper-fabric.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EACL,cAAc,EACd,iBAAiB,EAElB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,0BAA0B,
|
|
1
|
+
{"version":3,"file":"harper-fabric.d.ts","sourceRoot":"","sources":["../../../src/configs/eslint/harper-fabric.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EACL,cAAc,EACd,iBAAiB,EAElB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAE7C;;GAEG;AACH,eAAO,MAAM,0BAA0B,UAetC,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,eAAe,EACf,cAA2C,EAC3C,UAA8B,GAC/B,EAAE;IACD,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,iBAAiB,CAAC;CACvC,GAAG,MAAM,CAAC,MAAM,EAAE,CAkClB"}
|
|
@@ -11,6 +11,11 @@ export const defaultHarperFabricIgnores = [
|
|
|
11
11
|
"*.config.local.ts",
|
|
12
12
|
"harper-app/resources.js",
|
|
13
13
|
"harper-app/resource-*.js",
|
|
14
|
+
// Root-level compiled Harper modules (resources.js, resource-*.js, and any
|
|
15
|
+
// other build output emitted straight into harper-app/). The single-star does
|
|
16
|
+
// not cross a directory separator, so hand-written shims one level down
|
|
17
|
+
// (harper-app/<route>/index.js) are still linted.
|
|
18
|
+
"harper-app/*.js",
|
|
14
19
|
"harper-app/web/**",
|
|
15
20
|
"harper-app/lib/**",
|
|
16
21
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harper-fabric.js","sourceRoot":"","sources":["../../../src/configs/eslint/harper-fabric.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,GAAG,cAAc;IACjB,WAAW;IACX,UAAU;IACV,WAAW;IACX,mBAAmB;IACnB,yBAAyB;IACzB,0BAA0B;IAC1B,mBAAmB;IACnB,mBAAmB;CACpB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,EACpC,eAAe,EACf,cAAc,GAAG,0BAA0B,EAC3C,UAAU,GAAG,iBAAiB,GAK/B;IACC,OAAO;QACL,GAAG,mBAAmB,CAAC;YACrB,eAAe;YACf,cAAc;YACd,UAAU;SACX,CAAC;QACF;YACE,KAAK,EAAE,CAAC,aAAa,CAAC;YACtB,KAAK,EAAE;gBACL,2BAA2B,EAAE,OAAO;gBACpC,mBAAmB,EAAE,OAAO;gBAC5B,iCAAiC,EAAE,OAAO;gBAC1C,0BAA0B,EAAE,OAAO;gBACnC,0CAA0C,EAAE,OAAO;aACpD;SACF;QACD;YACE,KAAK,EAAE,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;YACnD,KAAK,EAAE;gBACL,2BAA2B,EAAE,KAAK;gBAClC,mBAAmB,EAAE,KAAK;gBAC1B,iCAAiC,EAAE,KAAK;gBACxC,0BAA0B,EAAE,KAAK;gBACjC,0CAA0C,EAAE,KAAK;aAClD;SACF;QACD;YACE,KAAK,EAAE,CAAC,qBAAqB,EAAE,eAAe,CAAC;YAC/C,KAAK,EAAE;gBACL,sBAAsB,EAAE,KAAK;aAC9B;SACF;KACiB,CAAC;AACvB,CAAC"}
|
|
1
|
+
{"version":3,"file":"harper-fabric.js","sourceRoot":"","sources":["../../../src/configs/eslint/harper-fabric.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAE7C;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,GAAG,cAAc;IACjB,WAAW;IACX,UAAU;IACV,WAAW;IACX,mBAAmB;IACnB,yBAAyB;IACzB,0BAA0B;IAC1B,2EAA2E;IAC3E,8EAA8E;IAC9E,wEAAwE;IACxE,kDAAkD;IAClD,iBAAiB;IACjB,mBAAmB;IACnB,mBAAmB;CACpB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,EACpC,eAAe,EACf,cAAc,GAAG,0BAA0B,EAC3C,UAAU,GAAG,iBAAiB,GAK/B;IACC,OAAO;QACL,GAAG,mBAAmB,CAAC;YACrB,eAAe;YACf,cAAc;YACd,UAAU;SACX,CAAC;QACF;YACE,KAAK,EAAE,CAAC,aAAa,CAAC;YACtB,KAAK,EAAE;gBACL,2BAA2B,EAAE,OAAO;gBACpC,mBAAmB,EAAE,OAAO;gBAC5B,iCAAiC,EAAE,OAAO;gBAC1C,0BAA0B,EAAE,OAAO;gBACnC,0CAA0C,EAAE,OAAO;aACpD;SACF;QACD;YACE,KAAK,EAAE,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;YACnD,KAAK,EAAE;gBACL,2BAA2B,EAAE,KAAK;gBAClC,mBAAmB,EAAE,KAAK;gBAC1B,iCAAiC,EAAE,KAAK;gBACxC,0BAA0B,EAAE,KAAK;gBACjC,0CAA0C,EAAE,KAAK;aAClD;SACF;QACD;YACE,KAAK,EAAE,CAAC,qBAAqB,EAAE,eAAe,CAAC;YAC/C,KAAK,EAAE;gBACL,sBAAsB,EAAE,KAAK;aAC9B;SACF;KACiB,CAAC;AACvB,CAAC"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# BEGIN: AI GUARDRAILS HARPER-FABRIC
|
|
2
|
+
# Compiled Harper modules are emitted straight into harper-app/ from src/. The
|
|
3
|
+
# root-level `harper-app/*.js` rule covers resources.js, resource-*.js, and any
|
|
4
|
+
# other build output (e.g. detail-shell-negotiation.js) without matching
|
|
5
|
+
# hand-written shims nested one level down (harper-app/<route>/index.js). If you
|
|
6
|
+
# keep a hand-written .js at the harper-app root (e.g. an SEO shell), re-include
|
|
7
|
+
# it with a `!harper-app/<file>.js` line placed BELOW this managed block.
|
|
2
8
|
harper-app/resources.js
|
|
3
9
|
harper-app/resource-*.js
|
|
10
|
+
harper-app/*.js
|
|
4
11
|
harper-app/web/**
|
|
5
12
|
harper-app/lib/**
|
|
6
13
|
.lisabak/
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
|
|
4
|
+
# Harper/Fabric override of the TypeScript dependabot template.
|
|
5
|
+
# A fresh Harper/Fabric repo ships with only a `main` branch, so this file
|
|
6
|
+
# omits `target-branch` — Dependabot then opens PRs against the repository's
|
|
7
|
+
# default branch instead of a `dev` branch that does not exist. If a project
|
|
8
|
+
# adopts a long-lived integration branch, set `target-branch` back per updater.
|
|
9
|
+
|
|
10
|
+
version: 2
|
|
11
|
+
updates:
|
|
12
|
+
# JavaScript/Node.js dependencies
|
|
13
|
+
- package-ecosystem: npm
|
|
14
|
+
directory: /
|
|
15
|
+
schedule:
|
|
16
|
+
interval: weekly
|
|
17
|
+
day: monday
|
|
18
|
+
open-pull-requests-limit: 10
|
|
19
|
+
groups:
|
|
20
|
+
production-dependencies:
|
|
21
|
+
dependency-type: production
|
|
22
|
+
update-types:
|
|
23
|
+
- minor
|
|
24
|
+
- patch
|
|
25
|
+
development-dependencies:
|
|
26
|
+
dependency-type: development
|
|
27
|
+
update-types:
|
|
28
|
+
- minor
|
|
29
|
+
- patch
|
|
30
|
+
labels:
|
|
31
|
+
- dependencies
|
|
32
|
+
commit-message:
|
|
33
|
+
prefix: 'chore(deps)'
|
|
34
|
+
prefix-development: 'chore(deps-dev)'
|
|
35
|
+
|
|
36
|
+
# GitHub Actions
|
|
37
|
+
- package-ecosystem: github-actions
|
|
38
|
+
directory: /
|
|
39
|
+
schedule:
|
|
40
|
+
interval: weekly
|
|
41
|
+
day: monday
|
|
42
|
+
open-pull-requests-limit: 5
|
|
43
|
+
labels:
|
|
44
|
+
- dependencies
|
|
45
|
+
- github-actions
|
|
46
|
+
commit-message:
|
|
47
|
+
prefix: 'ci(deps)'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
id: harper-no-early-return-in-search-loop
|
|
4
|
+
language: typescript
|
|
5
|
+
severity: warning
|
|
6
|
+
message: |
|
|
7
|
+
Early `return`/`break` out of a `for await (... of tables.X.search(...))` loop
|
|
8
|
+
leaves Harper's read transaction open — the iterator is abandoned before the
|
|
9
|
+
scan completes and the transaction is not released, leaking a read handle.
|
|
10
|
+
note: >-
|
|
11
|
+
Drain or explicitly close the iterator on early exit. Prefer bounding the query
|
|
12
|
+
so the loop finishes naturally (`search({ ..., limit: 1 })` when you only need
|
|
13
|
+
the first row), or drive the iterator manually and call `iterator.return?.()`
|
|
14
|
+
in a `finally` block so Harper releases the read transaction. This is a
|
|
15
|
+
heuristic — a `break` that belongs to an inner `switch` or a `return` inside a
|
|
16
|
+
nested callback is a false positive; suppress those with an inline
|
|
17
|
+
`// ast-grep-ignore: harper-no-early-return-in-search-loop`.
|
|
18
|
+
rule:
|
|
19
|
+
any:
|
|
20
|
+
- kind: return_statement
|
|
21
|
+
- kind: break_statement
|
|
22
|
+
inside:
|
|
23
|
+
kind: for_in_statement
|
|
24
|
+
stopBy: end
|
|
25
|
+
has:
|
|
26
|
+
field: right
|
|
27
|
+
pattern: $ITER.search($$$ARGS)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
id: harper-no-empty-conditions-with-sort
|
|
4
|
+
language: typescript
|
|
5
|
+
severity: error
|
|
6
|
+
message: |
|
|
7
|
+
A Harper `search()` with `sort` but an empty `conditions: []` array crashes
|
|
8
|
+
the query planner — it cannot seed the btree scan from the sort attribute and
|
|
9
|
+
throws at runtime (a latent 500 the first time an unfiltered, sorted page is
|
|
10
|
+
requested).
|
|
11
|
+
note: >-
|
|
12
|
+
Seed a floor/sentinel condition on the sort attribute so the planner has an
|
|
13
|
+
index range to walk, e.g. `{ attribute: "lastName", comparator:
|
|
14
|
+
"greater_than_equal", value: "" }` (or `not_equal: null`), then apply the sort.
|
|
15
|
+
Centralize this in the page helper (`searchPageAndCount`) rather than
|
|
16
|
+
duplicating a sentinel at each call site. If a sort-only scan is genuinely
|
|
17
|
+
intended and the attribute is guaranteed present, suppress with an inline
|
|
18
|
+
`// ast-grep-ignore: harper-no-empty-conditions-with-sort` and a comment.
|
|
19
|
+
rule:
|
|
20
|
+
kind: object
|
|
21
|
+
all:
|
|
22
|
+
- has:
|
|
23
|
+
kind: pair
|
|
24
|
+
all:
|
|
25
|
+
- has:
|
|
26
|
+
field: key
|
|
27
|
+
regex: ^conditions$
|
|
28
|
+
- has:
|
|
29
|
+
field: value
|
|
30
|
+
kind: array
|
|
31
|
+
regex: "^\\[\\s*\\]$"
|
|
32
|
+
- has:
|
|
33
|
+
kind: pair
|
|
34
|
+
has:
|
|
35
|
+
field: key
|
|
36
|
+
regex: ^sort$
|
|
37
|
+
inside:
|
|
38
|
+
kind: arguments
|
|
39
|
+
stopBy: end
|
|
40
|
+
inside:
|
|
41
|
+
kind: call_expression
|
|
42
|
+
stopBy: end
|
|
43
|
+
has:
|
|
44
|
+
field: function
|
|
45
|
+
regex: search$
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
id: harper-no-full-table-scan
|
|
4
|
+
language: typescript
|
|
5
|
+
severity: warning
|
|
6
|
+
message: |
|
|
7
|
+
Possible full table scan in a Harper resource. Loading a whole table on every
|
|
8
|
+
request does not scale — one large table (e.g. an employment/event history) was
|
|
9
|
+
the root cause of multi-second `/Search` and directory responses and a day-long
|
|
10
|
+
red deploy gate in production.
|
|
11
|
+
note: >-
|
|
12
|
+
Fetch only the rows you need through an indexed attribute
|
|
13
|
+
(`rowsByAttribute(tables.$TABLE, "someIndexedId", value)`), or page with
|
|
14
|
+
`searchPageAndCount` / `search({ conditions, limit, offset })`. A conditionless
|
|
15
|
+
`tables.$TABLE.search({})` / `search()` and the `allRows` / `optionalAll`
|
|
16
|
+
helpers read every row. Small lookup tables can be legitimate to scan — this is
|
|
17
|
+
a warning; if a full scan is genuinely intended (a one-off offline script, never
|
|
18
|
+
a Resource handler), suppress with an inline
|
|
19
|
+
`// ast-grep-ignore: harper-no-full-table-scan` and a comment saying why.
|
|
20
|
+
rule:
|
|
21
|
+
any:
|
|
22
|
+
# Non-generic full-table reads via common directory helpers.
|
|
23
|
+
- pattern: allRows(tables.$TABLE)
|
|
24
|
+
- pattern: optionalAll(tables.$TABLE)
|
|
25
|
+
# Generic form, e.g. allRows<AdvisorRow>(tables.Advisor): the type argument
|
|
26
|
+
# nests the callee in an instantiation_expression, so the plain patterns
|
|
27
|
+
# above miss it. Any single-arg generic call passing the whole table is a
|
|
28
|
+
# full scan regardless of helper name (the scoped rowsByAttribute helper
|
|
29
|
+
# takes 3 args and is not matched).
|
|
30
|
+
- pattern: $FN<$TYPE>(tables.$TABLE)
|
|
31
|
+
# Raw unconditional table scans.
|
|
32
|
+
- pattern: tables.$TABLE.search({})
|
|
33
|
+
- pattern: tables.$TABLE.search()
|
package/harper-fabric/copy-overwrite/ast-grep/rules/harper/require-statuscode-on-thrown-error.yml
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# This file is managed by Lisa.
|
|
2
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
3
|
+
id: harper-require-statuscode-on-thrown-error
|
|
4
|
+
language: typescript
|
|
5
|
+
severity: error
|
|
6
|
+
message: |
|
|
7
|
+
This error carries `status` but not `statusCode`. Harper's thrown-error HTTP
|
|
8
|
+
response writer reads `error.statusCode` (falling back to 500); a plain
|
|
9
|
+
`status` is ignored, so every intended 4xx becomes a 500 on the wire.
|
|
10
|
+
note: >-
|
|
11
|
+
Set `statusCode` (keep `status` too if callers/tests rely on it):
|
|
12
|
+
`Object.assign(error, { status, statusCode: status })`, or in an Error
|
|
13
|
+
subclass assign `this.statusCode = status` alongside `this.status`. Verified
|
|
14
|
+
live on harperdb 4.7.32 — a 401/403/404 thrown with only `status` was served
|
|
15
|
+
as 500. Direct `err.status = code` assignments are not auto-detected; when you
|
|
16
|
+
attach an HTTP code to a thrown error, always set `statusCode`.
|
|
17
|
+
rule:
|
|
18
|
+
any:
|
|
19
|
+
# `Object.assign(error, { status })` with only a `status` property — the
|
|
20
|
+
# exact object match excludes the correct `{ status, statusCode }` form.
|
|
21
|
+
- pattern: 'Object.assign($E, { status: $S })'
|
|
22
|
+
# Error subclass that assigns `this.status` but never mentions `statusCode`
|
|
23
|
+
# anywhere in the class body.
|
|
24
|
+
- pattern: this.status = $S
|
|
25
|
+
inside:
|
|
26
|
+
kind: class_declaration
|
|
27
|
+
stopBy: end
|
|
28
|
+
all:
|
|
29
|
+
- has:
|
|
30
|
+
kind: class_heritage
|
|
31
|
+
stopBy: end
|
|
32
|
+
has:
|
|
33
|
+
kind: extends_clause
|
|
34
|
+
has:
|
|
35
|
+
field: value
|
|
36
|
+
regex: Error$
|
|
37
|
+
- not:
|
|
38
|
+
has:
|
|
39
|
+
kind: property_identifier
|
|
40
|
+
regex: ^statusCode$
|
|
41
|
+
stopBy: end
|
package/package.json
CHANGED
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"ws": ">=8.20.1"
|
|
96
96
|
},
|
|
97
97
|
"name": "@codyswann/lisa",
|
|
98
|
-
"version": "2.
|
|
98
|
+
"version": "2.192.1",
|
|
99
99
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
100
100
|
"main": "dist/index.js",
|
|
101
101
|
"exports": {
|
|
@@ -33,6 +33,7 @@ matches_glob() {
|
|
|
33
33
|
local file="$1"
|
|
34
34
|
local glob="$2"
|
|
35
35
|
|
|
36
|
+
# Recursive directory globs: "dir/**" matches everything under dir.
|
|
36
37
|
if [ "${glob: -3}" = "/**" ]; then
|
|
37
38
|
local dir="${glob%/**}"
|
|
38
39
|
case "$file" in
|
|
@@ -41,6 +42,38 @@ matches_glob() {
|
|
|
41
42
|
return 1
|
|
42
43
|
fi
|
|
43
44
|
|
|
45
|
+
# Single-star globs like "harper-app/*.js": the star must not cross a
|
|
46
|
+
# directory separator, so a broadened root-level pattern protects compiled
|
|
47
|
+
# modules emitted straight into harper-app/ (resources.js, resource-*.js, and
|
|
48
|
+
# any other build output such as detail-shell-negotiation.js) WITHOUT matching
|
|
49
|
+
# hand-written files nested one level down (e.g. harper-app/<route>/index.js).
|
|
50
|
+
case "$glob" in
|
|
51
|
+
*/\** | \**)
|
|
52
|
+
local base_glob="${glob##*/}"
|
|
53
|
+
local dir_glob=""
|
|
54
|
+
case "$glob" in
|
|
55
|
+
*/*) dir_glob="${glob%/*}" ;;
|
|
56
|
+
esac
|
|
57
|
+
local file_base="${file##*/}"
|
|
58
|
+
local file_dir=""
|
|
59
|
+
case "$file" in
|
|
60
|
+
*/*) file_dir="${file%/*}" ;;
|
|
61
|
+
esac
|
|
62
|
+
case "$file_base" in
|
|
63
|
+
$base_glob) ;;
|
|
64
|
+
*) return 1 ;;
|
|
65
|
+
esac
|
|
66
|
+
[ -z "$dir_glob" ] && return 0
|
|
67
|
+
# Match the directory exactly, or as a suffix so absolute/prefixed paths
|
|
68
|
+
# (e.g. /repo/harper-app/foo.js) still resolve.
|
|
69
|
+
case "$file_dir" in
|
|
70
|
+
$dir_glob | */"$dir_glob") return 0 ;;
|
|
71
|
+
esac
|
|
72
|
+
return 1
|
|
73
|
+
;;
|
|
74
|
+
esac
|
|
75
|
+
|
|
76
|
+
# Literal (wildcard-free) globs.
|
|
44
77
|
case "$file" in
|
|
45
78
|
$glob | */$glob) return 0 ;;
|
|
46
79
|
esac
|
|
@@ -50,6 +83,24 @@ matches_glob() {
|
|
|
50
83
|
|
|
51
84
|
NORMALIZED_FILE=$(normalize_path "$FILE_PATH")
|
|
52
85
|
|
|
86
|
+
# Project-owned allowlist of hand-written files that live under harper-app/ and
|
|
87
|
+
# must NOT be treated as generated (e.g. a hand-authored SEO shell, or route
|
|
88
|
+
# index.js shims kept at the harper-app root). The broadened root-level
|
|
89
|
+
# `harper-app/*.js` protection would otherwise block editing them. One glob per
|
|
90
|
+
# line (same syntax as the globs file); blank lines and `#` comments ignored.
|
|
91
|
+
# Prefer naming compiled resource modules `resource-*.ts` so their JS output is
|
|
92
|
+
# unambiguously generated and never needs allowlisting.
|
|
93
|
+
ALLOWLIST_FILE="${CLAUDE_PROJECT_DIR:-.}/.lisa/harper-generated-artifact-allowlist.txt"
|
|
94
|
+
if [ -f "$ALLOWLIST_FILE" ]; then
|
|
95
|
+
while IFS= read -r allow || [ -n "$allow" ]; do
|
|
96
|
+
[ -n "$allow" ] || continue
|
|
97
|
+
case "$allow" in \#*) continue ;; esac
|
|
98
|
+
if matches_glob "$NORMALIZED_FILE" "$allow"; then
|
|
99
|
+
exit 0
|
|
100
|
+
fi
|
|
101
|
+
done <"$ALLOWLIST_FILE"
|
|
102
|
+
fi
|
|
103
|
+
|
|
53
104
|
while IFS= read -r glob || [ -n "$glob" ]; do
|
|
54
105
|
[ -n "$glob" ] || continue
|
|
55
106
|
case "$glob" in \#*) continue ;; esac
|
|
@@ -13,7 +13,7 @@ These rules apply to Harper/Fabric component apps managed by Lisa.
|
|
|
13
13
|
- TypeScript under `src/` is the source of truth for Harper resources, browser modules, shared libraries, and operational scripts.
|
|
14
14
|
- `harper-app/config.yaml`, `harper-app/schema.graphql`, HTML, CSS, docs, and research fixtures are source assets.
|
|
15
15
|
- `harper-app/config.yaml` does not merge with Harper defaults. Keep every required top-level extension declared when editing it; the Harper Fabric hook blocks accidental extension drops unless the removal is documented in `.lisa/harper-config-extension-allowlist.json`.
|
|
16
|
-
- `harper-app
|
|
16
|
+
- Every `.js` at the harper-app root (`harper-app/*.js` — `resources.js`, `resource-*.js`, and any other compiled module) plus `harper-app/web/**/*.js` and `harper-app/lib/**` are generated deploy artifacts. Never edit them directly; change the matching TypeScript and run `bun run build`. Name compiled resource modules `resource-*.ts` so their output is unambiguously generated; a hand-written `.js` kept at the harper-app root must be re-included in `.gitignore` and listed in `.lisa/harper-generated-artifact-allowlist.txt` so the block hook allows editing it.
|
|
17
17
|
- Deployment, bootstrap, smoke, seed, verify, preview, token, crawl, ingest, and extraction commands must run from compiled JavaScript or generated Harper assets, not stale checked-in JavaScript.
|
|
18
18
|
|
|
19
19
|
## Harper/Fabric Deploy Surface
|
|
@@ -260,6 +260,54 @@ Guidance:
|
|
|
260
260
|
webhook must bypass Harper auth, verify its signature first and keep its table
|
|
261
261
|
writes narrowly scoped.
|
|
262
262
|
|
|
263
|
+
## Session cookies are `SameSite=None` — guard state-changing POSTs
|
|
264
|
+
|
|
265
|
+
Harper hardcodes the session cookie's `SameSite=None` attribute on HTTPS. The
|
|
266
|
+
browser therefore attaches the session cookie to **cross-site** requests, so a
|
|
267
|
+
same-origin app cannot rely on `SameSite` to block CSRF on cookie-authenticated,
|
|
268
|
+
state-changing routes (`POST`/`PUT`/`PATCH`/`DELETE`).
|
|
269
|
+
|
|
270
|
+
Add an app-side origin check in the resource before mutating. Reject requests
|
|
271
|
+
whose `Origin` (or `Referer` fallback) is not an allowed origin:
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
const ALLOWED_ORIGINS = new Set([
|
|
275
|
+
'https://app.example.com',
|
|
276
|
+
]);
|
|
277
|
+
|
|
278
|
+
function requireSameOrigin(context) {
|
|
279
|
+
const headers = context.requestContext?.headers ?? context.headers;
|
|
280
|
+
const origin =
|
|
281
|
+
headers?.get?.('origin') ??
|
|
282
|
+
headers?.get?.('referer');
|
|
283
|
+
const ok =
|
|
284
|
+
typeof origin === 'string' &&
|
|
285
|
+
[...ALLOWED_ORIGINS].some((allowed) => origin.startsWith(allowed));
|
|
286
|
+
if (!ok) {
|
|
287
|
+
const error = new Error('Cross-origin request rejected');
|
|
288
|
+
error.statusCode = 403; // Harper reads statusCode, not status
|
|
289
|
+
throw error;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export class Watchlists extends tables.Watchlists {
|
|
294
|
+
static async post(target, data, context) {
|
|
295
|
+
requireSameOrigin(context);
|
|
296
|
+
// ...authorization and write
|
|
297
|
+
return super.post(target, await data, context);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Guidance:
|
|
303
|
+
|
|
304
|
+
- Call the check on every cookie-authenticated state-changing route. Read-only
|
|
305
|
+
`GET` handlers and token/`Authorization: Bearer` APIs (not cookie-driven) do
|
|
306
|
+
not need it.
|
|
307
|
+
- Prefer an allowlist of exact origins over substring matching that a lookalike
|
|
308
|
+
host could satisfy.
|
|
309
|
+
- This is defense the app owns; Harper will not add it for you.
|
|
310
|
+
|
|
263
311
|
## Verification matrix
|
|
264
312
|
|
|
265
313
|
Run the local app, create the test users, and check unauthenticated, reader, and
|
|
@@ -50,15 +50,30 @@ What the build actually does:
|
|
|
50
50
|
|
|
51
51
|
Generated Harper deploy artifacts usually include:
|
|
52
52
|
|
|
53
|
-
- `harper-app
|
|
54
|
-
|
|
53
|
+
- `harper-app/*.js` — every compiled module the build emits to the harper-app
|
|
54
|
+
root (`resources.js`, `resource-*.js`, and any other output such as a route
|
|
55
|
+
negotiation module). The single-star does **not** cross a directory separator,
|
|
56
|
+
so it does not match hand-written shims one level down.
|
|
55
57
|
- `harper-app/web/**`
|
|
56
58
|
- `harper-app/lib/**`
|
|
57
59
|
|
|
60
|
+
The guard surfaces (`generated-artifact-globs.txt` for the PreToolUse block hook,
|
|
61
|
+
`.gitignore`, `.prettierignore`, the ESLint/oxlint/knip ignores, and
|
|
62
|
+
`tsconfig.eslint.json`) all key off `harper-app/*.js` so a newly-named compiled
|
|
63
|
+
module is protected automatically. **Name compiled resource modules
|
|
64
|
+
`resource-*.ts`** so their JS output is unambiguously generated.
|
|
65
|
+
|
|
66
|
+
If you keep a *hand-written* `.js` at the harper-app root (e.g. an SEO shell),
|
|
67
|
+
the root-level rule would otherwise treat it as generated: re-include it with a
|
|
68
|
+
`!harper-app/<file>.js` line below the managed gitignore block, and add it to
|
|
69
|
+
`.lisa/harper-generated-artifact-allowlist.txt` so the block hook lets you edit
|
|
70
|
+
it. Hand-written shims nested under `harper-app/<route>/index.js` need no
|
|
71
|
+
exemption — the root-level rule never matches them.
|
|
72
|
+
|
|
58
73
|
Every lint, format, dead-code, search, or generated-artifact guard must ignore
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
same change; partial ignores fail later gates in non-obvious ways.
|
|
74
|
+
generated paths unless it is explicitly validating the build output itself. When
|
|
75
|
+
a new generated *directory* appears, add it to every relevant ignore surface in
|
|
76
|
+
the same change; partial ignores fail later gates in non-obvious ways.
|
|
62
77
|
|
|
63
78
|
- **TypeScript under `src/` is source.** `bun run build` produces the deployable
|
|
64
79
|
Harper assets from it.
|