@codyswann/lisa 2.191.13 → 2.192.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.
Files changed (71) hide show
  1. package/harper-fabric/copy-overwrite/.github/dependabot.yml +47 -0
  2. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-early-return-in-search-loop.yml +27 -0
  3. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-empty-conditions-with-sort.yml +45 -0
  4. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/no-full-table-scan.yml +33 -0
  5. package/harper-fabric/copy-overwrite/ast-grep/rules/harper/require-statuscode-on-thrown-error.yml +41 -0
  6. package/package.json +2 -2
  7. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  8. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  9. package/plugins/lisa-agy/plugin.json +1 -1
  10. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  13. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-expo-agy/plugin.json +1 -1
  20. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  24. package/plugins/lisa-harper-fabric/skills/harper-auth/SKILL.md +48 -0
  25. package/plugins/lisa-harper-fabric/skills/harper-resources/SKILL.md +35 -0
  26. package/plugins/lisa-harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
  27. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  28. package/plugins/lisa-harper-fabric-agy/skills/harper-auth/SKILL.md +48 -0
  29. package/plugins/lisa-harper-fabric-agy/skills/harper-resources/SKILL.md +35 -0
  30. package/plugins/lisa-harper-fabric-agy/skills/harper-rest-queries/SKILL.md +40 -3
  31. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-copilot/skills/harper-auth/SKILL.md +48 -0
  33. package/plugins/lisa-harper-fabric-copilot/skills/harper-resources/SKILL.md +35 -0
  34. package/plugins/lisa-harper-fabric-copilot/skills/harper-rest-queries/SKILL.md +40 -3
  35. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-cursor/skills/harper-auth/SKILL.md +48 -0
  37. package/plugins/lisa-harper-fabric-cursor/skills/harper-resources/SKILL.md +35 -0
  38. package/plugins/lisa-harper-fabric-cursor/skills/harper-rest-queries/SKILL.md +40 -3
  39. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  52. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-agy/plugin.json +1 -1
  57. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  62. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  67. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/src/harper-fabric/skills/harper-auth/SKILL.md +48 -0
  70. package/plugins/src/harper-fabric/skills/harper-resources/SKILL.md +35 -0
  71. package/plugins/src/harper-fabric/skills/harper-rest-queries/SKILL.md +40 -3
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.191.13",
3
+ "version": "2.192.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.191.13",
3
+ "version": "2.192.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -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
@@ -74,6 +74,41 @@ See [[harper-config-yaml]] for the extension wiring, [[harper-schema-graphql]] f
74
74
  how the schema defines the tables resources extend, and [[harper-realtime]] when
75
75
  `subscribe`, `publish`, or WebSocket behavior is part of the feature.
76
76
 
77
+ ## Throwing HTTP status errors
78
+
79
+ Harper's thrown-error response writer reads **`error.statusCode`** (falling back
80
+ to `500`). A plain `error.status` is **ignored** — throw an error with only
81
+ `status` set and every intended `4xx` is served as a `500`. Verified on
82
+ harperdb 4.7.32.
83
+
84
+ Always set `statusCode` (keep `status` too only if callers or tests read it):
85
+
86
+ ```javascript
87
+ static async post(target, data, context) {
88
+ if (!context.user) {
89
+ const error = new Error('Authentication required');
90
+ error.statusCode = 401; // NOT `error.status` — Harper reads statusCode
91
+ throw error;
92
+ }
93
+ // ...
94
+ }
95
+ ```
96
+
97
+ A shared helper keeps every throw site correct:
98
+
99
+ ```javascript
100
+ function throwStatus(message, status) {
101
+ // Set both: `statusCode` is what Harper serves; `status` is kept for
102
+ // returned-response symmetry and any caller/test that reads it.
103
+ throw Object.assign(new Error(message), { status, statusCode: status });
104
+ }
105
+ ```
106
+
107
+ The `harper-require-statuscode-on-thrown-error` ast-grep rule flags errors that
108
+ carry `status` without `statusCode`. Pass `context` through to `super` and nested
109
+ table calls so authorization and the request transaction stay aligned — see
110
+ [[harper-rest-queries]] for context propagation and iterator draining.
111
+
77
112
  ## Project conventions (TS is source)
78
113
 
79
114
  - **Write resources in TypeScript under `src/`. `harper-app/resources.js` is a
@@ -121,6 +121,38 @@ const products = await tables.Products.search({
121
121
  });
122
122
  ```
123
123
 
124
+ ## Sort with no conditions crashes the planner
125
+
126
+ A `search()` that carries a `sort` but an **empty `conditions: []`** array throws
127
+ at runtime — the planner cannot seed the btree scan from the sort attribute. This
128
+ is a latent `500` the first time an unfiltered, sorted collection page is
129
+ requested (verified on harperdb 4.7.32).
130
+
131
+ ```javascript
132
+ // ✗ crashes: sort with nothing to seed the scan
133
+ tables.Advisor.search({
134
+ conditions: [],
135
+ sort: { attribute: 'lastName' },
136
+ });
137
+ ```
138
+
139
+ Seed a floor/sentinel condition on the sort attribute so the planner has an index
140
+ range to walk, then apply the sort:
141
+
142
+ ```javascript
143
+ // ✓ floor condition on the sort attribute seeds the scan
144
+ tables.Advisor.search({
145
+ conditions: [
146
+ { attribute: 'lastName', comparator: 'greater_than_equal', value: '' },
147
+ ],
148
+ sort: { attribute: 'lastName' },
149
+ });
150
+ ```
151
+
152
+ Centralize this in the page helper (`searchPageAndCount`) rather than duplicating
153
+ a sentinel at each call site. The `harper-no-empty-conditions-with-sort` ast-grep
154
+ rule flags the crashing shape.
155
+
124
156
  ## Relationship queries
125
157
 
126
158
  Relationship attributes can be queried with dot syntax when the relationship is
@@ -200,9 +232,14 @@ Useful query keys:
200
232
  | `select` | Projection list. Keep admin-only fields out of public responses. |
201
233
  | `explain` | Debug execution order and index usage while tuning. |
202
234
 
203
- `search()` can return an `AsyncIterable`. When iterating manually or stopping
204
- early, drain it or call the iterator's `return()` in `finally` so Harper can
205
- release the read transaction:
235
+ `search()` can return an `AsyncIterable`. An early `return`/`break` out of a
236
+ `for await (... of tables.X.search(...))` loop abandons the iterator before the
237
+ scan completes and **leaks the open read transaction** (verified on
238
+ harperdb 4.7.32). When iterating manually or stopping early, drain it or call the
239
+ iterator's `return()` in `finally` so Harper releases the read transaction — or
240
+ bound the query (`search({ ..., limit: 1 })`) when you only need the first row.
241
+ The `harper-no-early-return-in-search-loop` ast-grep rule flags early exits from
242
+ these loops:
206
243
 
207
244
  ```javascript
208
245
  const iterator = tables.Products