@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.
Files changed (98) hide show
  1. package/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
  2. package/dist/configs/eslint/harper-fabric.js +5 -0
  3. package/dist/configs/eslint/harper-fabric.js.map +1 -1
  4. package/harper-fabric/copy-contents/.prettierignore +1 -0
  5. package/harper-fabric/copy-contents/gitignore +7 -0
  6. package/harper-fabric/copy-overwrite/.github/dependabot.yml +47 -0
  7. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-early-return-in-search-loop.yml +27 -0
  8. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-empty-conditions-with-sort.yml +45 -0
  9. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-full-table-scan.yml +33 -0
  10. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/require-statuscode-on-thrown-error.yml +41 -0
  11. package/harper-fabric/copy-overwrite/knip.json +1 -0
  12. package/harper-fabric/copy-overwrite/tsconfig.eslint.json +1 -0
  13. package/harper-fabric/merge/.oxlintrc.json +1 -0
  14. package/oxlint/harper-fabric.json +1 -0
  15. package/package.json +1 -1
  16. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  22. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo-agy/plugin.json +1 -1
  29. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/generated-artifact-globs.txt +1 -0
  34. package/plugins/lisa-harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
  35. package/plugins/lisa-harper-fabric/rules/harper-fabric.md +1 -1
  36. package/plugins/lisa-harper-fabric/skills/harper-auth/SKILL.md +48 -0
  37. package/plugins/lisa-harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
  38. package/plugins/lisa-harper-fabric/skills/harper-resources/SKILL.md +35 -0
  39. package/plugins/lisa-harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
  40. package/plugins/lisa-harper-fabric-agy/generated-artifact-globs.txt +1 -0
  41. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-agy/skills/harper-auth/SKILL.md +48 -0
  43. package/plugins/lisa-harper-fabric-agy/skills/harper-build-and-deploy/SKILL.md +20 -5
  44. package/plugins/lisa-harper-fabric-agy/skills/harper-resources/SKILL.md +35 -0
  45. package/plugins/lisa-harper-fabric-agy/skills/harper-rest-queries/SKILL.md +40 -3
  46. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric-copilot/generated-artifact-globs.txt +1 -0
  48. package/plugins/lisa-harper-fabric-copilot/hooks/block-generated-artifact-edits.sh +51 -0
  49. package/plugins/lisa-harper-fabric-copilot/rules/harper-fabric.md +1 -1
  50. package/plugins/lisa-harper-fabric-copilot/skills/harper-auth/SKILL.md +48 -0
  51. package/plugins/lisa-harper-fabric-copilot/skills/harper-build-and-deploy/SKILL.md +20 -5
  52. package/plugins/lisa-harper-fabric-copilot/skills/harper-resources/SKILL.md +35 -0
  53. package/plugins/lisa-harper-fabric-copilot/skills/harper-rest-queries/SKILL.md +40 -3
  54. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-harper-fabric-cursor/generated-artifact-globs.txt +1 -0
  56. package/plugins/lisa-harper-fabric-cursor/hooks/block-generated-artifact-edits.sh +51 -0
  57. package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +1 -1
  58. package/plugins/lisa-harper-fabric-cursor/skills/harper-auth/SKILL.md +48 -0
  59. package/plugins/lisa-harper-fabric-cursor/skills/harper-build-and-deploy/SKILL.md +20 -5
  60. package/plugins/lisa-harper-fabric-cursor/skills/harper-resources/SKILL.md +35 -0
  61. package/plugins/lisa-harper-fabric-cursor/skills/harper-rest-queries/SKILL.md +40 -3
  62. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  75. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails-agy/plugin.json +1 -1
  80. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  85. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  90. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  92. package/plugins/src/harper-fabric/generated-artifact-globs.txt +1 -0
  93. package/plugins/src/harper-fabric/hooks/block-generated-artifact-edits.sh +51 -0
  94. package/plugins/src/harper-fabric/rules/harper-fabric.md +1 -1
  95. package/plugins/src/harper-fabric/skills/harper-auth/SKILL.md +48 -0
  96. package/plugins/src/harper-fabric/skills/harper-build-and-deploy/SKILL.md +20 -5
  97. package/plugins/src/harper-fabric/skills/harper-resources/SKILL.md +35 -0
  98. 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,UAUtC,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"}
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"}
@@ -4,6 +4,7 @@
4
4
  # source formatting inputs.
5
5
  harper-app/resources.js
6
6
  harper-app/resource-*.js
7
+ harper-app/*.js
7
8
  harper-app/web/**
8
9
  harper-app/lib/**
9
10
  research/articles/
@@ -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()
@@ -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
@@ -15,6 +15,7 @@
15
15
  "**/node_modules/**",
16
16
  "harper-app/resources.js",
17
17
  "harper-app/resource-*.js",
18
+ "harper-app/*.js",
18
19
  "harper-app/web/**",
19
20
  "harper-app/lib/**"
20
21
  ],
@@ -22,6 +22,7 @@
22
22
  "coverage",
23
23
  "harper-app/resources.js",
24
24
  "harper-app/resource-*.js",
25
+ "harper-app/*.js",
25
26
  "harper-app/web/**",
26
27
  "harper-app/lib/**"
27
28
  ]
@@ -12,6 +12,7 @@
12
12
  "**/generated/**",
13
13
  "harper-app/resources.js",
14
14
  "harper-app/resource-*.js",
15
+ "harper-app/*.js",
15
16
  "harper-app/web/**",
16
17
  "harper-app/lib/**"
17
18
  ]
@@ -7,6 +7,7 @@
7
7
  "node_modules/**",
8
8
  "harper-app/resources.js",
9
9
  "harper-app/resource-*.js",
10
+ "harper-app/*.js",
10
11
  "harper-app/web/**",
11
12
  "harper-app/lib/**"
12
13
  ]
package/package.json CHANGED
@@ -95,7 +95,7 @@
95
95
  "ws": ">=8.20.1"
96
96
  },
97
97
  "name": "@codyswann/lisa",
98
- "version": "2.191.14",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.191.14",
3
+ "version": "2.192.1",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,4 +1,5 @@
1
1
  harper-app/resources.js
2
2
  harper-app/resource-*.js
3
+ harper-app/*.js
3
4
  harper-app/web/**
4
5
  harper-app/lib/**
@@ -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/resources.js` and `harper-app/web/**/*.js` are generated deploy artifacts. Never edit them directly; change the matching TypeScript and run `bun run build`.
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/resources.js`
54
- - `harper-app/resource-*.js`
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
- those generated paths unless it is explicitly validating the build output itself.
60
- When a new generated path appears, add it to every relevant ignore surface in the
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.