@codyswann/lisa 4.17.19 → 4.19.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 (102) hide show
  1. package/dist/cli/ui-config-write-document.d.ts +53 -0
  2. package/dist/cli/ui-config-write-document.d.ts.map +1 -0
  3. package/dist/cli/ui-config-write-document.js +212 -0
  4. package/dist/cli/ui-config-write-document.js.map +1 -0
  5. package/dist/cli/ui-config-write-patch-plan.d.ts +30 -0
  6. package/dist/cli/ui-config-write-patch-plan.d.ts.map +1 -0
  7. package/dist/cli/ui-config-write-patch-plan.js +151 -0
  8. package/dist/cli/ui-config-write-patch-plan.js.map +1 -0
  9. package/dist/cli/ui-config-write-persistence.d.ts +19 -0
  10. package/dist/cli/ui-config-write-persistence.d.ts.map +1 -0
  11. package/dist/cli/ui-config-write-persistence.js +294 -0
  12. package/dist/cli/ui-config-write-persistence.js.map +1 -0
  13. package/dist/cli/ui-config-write-property-edits.d.ts +40 -0
  14. package/dist/cli/ui-config-write-property-edits.d.ts.map +1 -0
  15. package/dist/cli/ui-config-write-property-edits.js +250 -0
  16. package/dist/cli/ui-config-write-property-edits.js.map +1 -0
  17. package/dist/cli/ui-config-write-provenance.d.ts +12 -0
  18. package/dist/cli/ui-config-write-provenance.d.ts.map +1 -0
  19. package/dist/cli/ui-config-write-provenance.js +29 -0
  20. package/dist/cli/ui-config-write-provenance.js.map +1 -0
  21. package/dist/cli/ui-config-write-root-identity.d.ts +25 -0
  22. package/dist/cli/ui-config-write-root-identity.d.ts.map +1 -0
  23. package/dist/cli/ui-config-write-root-identity.js +66 -0
  24. package/dist/cli/ui-config-write-root-identity.js.map +1 -0
  25. package/dist/cli/ui-config-write.d.ts.map +1 -1
  26. package/dist/cli/ui-config-write.js +47 -92
  27. package/dist/cli/ui-config-write.js.map +1 -1
  28. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  29. package/dist/core/lisa-owned-hash-ledger.js +14 -0
  30. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  31. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  32. package/dist/core/upstream-evidence-manifest.js +21 -5
  33. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  34. package/dist/sync/json-path.d.ts +10 -0
  35. package/dist/sync/json-path.d.ts.map +1 -1
  36. package/dist/sync/json-path.js +14 -0
  37. package/dist/sync/json-path.js.map +1 -1
  38. package/dist/sync/sync-population.d.ts +6 -0
  39. package/dist/sync/sync-population.d.ts.map +1 -1
  40. package/dist/sync/sync-population.js +8 -0
  41. package/dist/sync/sync-population.js.map +1 -1
  42. package/dist/utils/atomic-file-write.d.ts +5 -4
  43. package/dist/utils/atomic-file-write.d.ts.map +1 -1
  44. package/dist/utils/atomic-file-write.js +3 -0
  45. package/dist/utils/atomic-file-write.js.map +1 -1
  46. package/expo/copy-overwrite/scripts/bdd/baseline.mjs +10 -2
  47. package/expo/copy-overwrite/scripts/bdd/render.mjs +3 -2
  48. package/expo/copy-overwrite/scripts/bdd-matrix.mjs +3 -3
  49. package/package.json +7 -2
  50. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-agy/plugin.json +1 -1
  53. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  56. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-expo-agy/plugin.json +1 -1
  63. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  68. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  73. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  78. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  83. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa-rails-agy/plugin.json +1 -1
  88. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  92. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  93. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  97. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  98. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  100. package/scripts/check-ui-demo-data.mjs +102 -0
  101. package/ui/README.md +94 -8
  102. package/ui/index.html +901 -115
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.17.19",
3
+ "version": "4.19.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": "4.17.19",
3
+ "version": "4.19.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.17.19",
3
+ "version": "4.19.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": "4.17.19",
3
+ "version": "4.19.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": "4.17.19",
3
+ "version": "4.19.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"
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Evaluate the Lisa UI catalog in a code-generation-disabled VM and invoke the
5
+ * catalog's own renderer-aware audit. Keeping the audit in `ui/index.html`
6
+ * means the browser and repository guard cannot drift into different ideas of
7
+ * which values are renderable.
8
+ * @module scripts/check-ui-demo-data
9
+ */
10
+ import { readFileSync } from "node:fs";
11
+ import path from "node:path";
12
+ import vm from "node:vm";
13
+
14
+ import { invokedAsScript } from "./lib/invoked-as-script.mjs";
15
+
16
+ const START_MARKER = "/* LISA_UI_CATALOG_START */";
17
+ const END_MARKER = "/* LISA_UI_CATALOG_END */";
18
+ const DEFAULT_UI_FILE = path.resolve("ui/index.html");
19
+ const VM_TIMEOUT_MS = 2_000;
20
+
21
+ /**
22
+ * Extract exactly one bounded catalog program from the HTML document.
23
+ * @param {string} html - Complete UI HTML
24
+ * @returns {string} Catalog JavaScript including the shared audit seam
25
+ */
26
+ export function extractUiCatalogProgram(html) {
27
+ const start = html.indexOf(START_MARKER);
28
+ const end = html.indexOf(END_MARKER);
29
+ if (start === -1 || end === -1 || end <= start) {
30
+ throw new Error(
31
+ `UI catalog markers are missing or out of order (${START_MARKER}, ${END_MARKER})`
32
+ );
33
+ }
34
+ if (
35
+ html.indexOf(START_MARKER, start + START_MARKER.length) !== -1 ||
36
+ html.indexOf(END_MARKER, end + END_MARKER.length) !== -1
37
+ ) {
38
+ throw new Error("UI catalog markers must each occur exactly once");
39
+ }
40
+ return html.slice(start + START_MARKER.length, end);
41
+ }
42
+
43
+ /**
44
+ * Audit an HTML catalog and optionally exercise the live preparation path.
45
+ * @param {string} html - Complete UI HTML
46
+ * @param {{liveConfigPresent?: boolean, liveConfig?: unknown, filename?: string}} [options]
47
+ * @returns {{audit: {inspected: number, sections: number, violations: string[]}, preparation: object|null, catalog: object}}
48
+ */
49
+ export function inspectUiDemoData(html, options = {}) {
50
+ const context = vm.createContext(
51
+ {
52
+ __liveConfigPresent: options.liveConfigPresent === true,
53
+ __liveConfig: options.liveConfig,
54
+ },
55
+ {
56
+ codeGeneration: { strings: false, wasm: false },
57
+ name: "lisa-ui-demo-data-audit",
58
+ }
59
+ );
60
+ const program = `${extractUiCatalogProgram(html)}
61
+ const __auditResult = auditUiCatalog(DATA);
62
+ const __preparationResult = globalThis.__liveConfigPresent
63
+ ? prepareUiCatalogForLive(DATA, globalThis.__liveConfig)
64
+ : null;
65
+ globalThis.__inspectionResult = {
66
+ audit: __auditResult,
67
+ preparation: __preparationResult,
68
+ catalog: DATA
69
+ };
70
+ `;
71
+ // The bounded catalog source is intentionally executed in a context with
72
+ // string/wasm code generation disabled and a hard timeout. This is the
73
+ // guard's shared-seam contract, not application input.
74
+ // eslint-disable-next-line sonarjs/code-eval -- Evaluate only the extracted catalog inside the locked VM above.
75
+ vm.runInContext(program, context, {
76
+ displayErrors: true,
77
+ filename: options.filename || "ui/index.html#catalog",
78
+ timeout: VM_TIMEOUT_MS,
79
+ });
80
+ return context.__inspectionResult;
81
+ }
82
+
83
+ /** Run the repository guard against a supplied file or the real UI. */
84
+ function main() {
85
+ const file = path.resolve(process.argv[2] || DEFAULT_UI_FILE);
86
+ try {
87
+ const inspection = inspectUiDemoData(readFileSync(file, "utf8"), {
88
+ filename: file,
89
+ });
90
+ process.stdout.write(
91
+ `[ui-demo-data] PASS: inspected ${inspection.audit.inspected} rendered values across ${inspection.audit.sections} sections\n`
92
+ );
93
+ } catch (error) {
94
+ const message = error instanceof Error ? error.message : String(error);
95
+ process.stderr.write(`[ui-demo-data] FAIL: ${message}\n`);
96
+ process.exitCode = 1;
97
+ }
98
+ }
99
+
100
+ if (invokedAsScript(import.meta.url)) {
101
+ main();
102
+ }
package/ui/README.md CHANGED
@@ -4,14 +4,13 @@ A self-contained, zero-build prototype of the Lisa settings console. It catalogs
4
4
  every configuration surface Lisa exposes to host projects and presents it as a
5
5
  navigable, editable-looking settings UI.
6
6
 
7
- **Prototype scope:** every control is interactive (toggles, selects, inputs,
8
- tabs, dirty-state tracking, save bar). Reading real values IS wired up: see
9
- `lisa ui` below. Persistence is partial and the line to read is
10
- `src/sync/registry.ts`: a control whose config key is in `SYNC_REGISTRY` is
11
- written to `.lisa.config.json` through `POST /api/config`; every other control
12
- still only clears the in-memory dirty state on "Save". `gates` is **not** a
13
- registry key, so no console write can touch a gate declaration today — which is
14
- why the Doctor section reports and never repairs.
7
+ **Prototype scope:** controls, tabs, dirty-state tracking, and the save bar are
8
+ interactive. Reading real values IS wired up: see `lisa ui` below. The backend
9
+ write contract now routes authorized keys through `POST /api/config`, but the
10
+ page's **Save changes** button deliberately remains disabled until the separate
11
+ save/rehydration UX ships. `gates` is **not** a registry key, so no console
12
+ write can touch a gate declaration today — which is why the Doctor section
13
+ reports and never repairs.
15
14
 
16
15
  ## Run it
17
16
 
@@ -31,6 +30,93 @@ live config it falls back to Lisa's shipped defaults:
31
30
  open ui/index.html
32
31
  ```
33
32
 
33
+ ## Demo-data boundary
34
+
35
+ The standalone and CLI-served paths deliberately have different data
36
+ contracts. Opening `ui/index.html` directly leaves
37
+ `window.LISA_LIVE_CONFIG` absent and renders the fictional demo catalog. The
38
+ CLI defines that property before the page boots, so the console enters live
39
+ mode even when the injected value is `false`, `0`, an empty string, or `null`.
40
+ Live mode scrubs every `demoOnly` block and row before the first render, keeps
41
+ present falsey configuration values, turns missing configuration keys into
42
+ `unknown`, and initializes probe/API values as pending or unknown. An empty
43
+ live section and a filter with no matches both render a generic empty/unknown
44
+ state; neither falls back to a demo value on a later render.
45
+
46
+ Every renderer-bearing catalog value must declare exactly one provenance:
47
+
48
+ - `key` for a value hydrated from `LISA_LIVE_CONFIG`;
49
+ - `liveSource` for a probe, API, or injected live snapshot;
50
+ - `demoOnly: true` for intentional direct-file sample data; or
51
+ - `staticCopy` with a narrow reason for fixed Lisa documentation or semantics.
52
+
53
+ The browser and repository guard invoke the same renderer-aware catalog audit.
54
+ It discovers the current sections and values rather than relying on a hardcoded
55
+ count, fails on unclassified or multiply classified values, and fails if it
56
+ inspects nothing. Run it after adding or changing console data:
57
+
58
+ ```bash
59
+ bun run check:ui-demo-data
60
+ ```
61
+
62
+ `acme/acme-app` is not a forbidden string: a live project can legitimately use
63
+ that name. The boundary is provenance, not a sentinel grep.
64
+
65
+ ## Config write contract (`POST /api/config`)
66
+
67
+ The same-origin endpoint classifies the complete request before reading either
68
+ config file. A key equal to a live `SYNC_REGISTRY` root, or below that root on a
69
+ dot-segment boundary, belongs in the committed `.lisa.config.json`. Exactly
70
+ three console-authorized developer keys belong in the gitignored
71
+ `.lisa.config.local.json`: `atlassian.email`, `intake.assignee`, and
72
+ `playStore.serviceAccountKeyPath`. Every other key — including `tracker`,
73
+ `jira.verified_workflow_hash`, prefix lookalikes, and descendants of a local
74
+ key — is rejected with HTTP 400 before file I/O. Responses contain the
75
+ committed config only, so a local value is never echoed.
76
+
77
+ Both documents remain strict JSON. Writes first compute the complete prospective
78
+ objects, then apply deterministic non-overlapping `jsonc-parser` syntax-tree
79
+ edits against the original text. Existing values replace only their value-node
80
+ range; removals consume only targeted property runs and required commas; missing
81
+ properties insert at stable object offsets. No edit range includes an unrelated
82
+ property node, so bytes outside the targeted spans retain their hand-authored
83
+ formatting even when one request mixes reconciliation and insertion in both
84
+ files. The project root is canonicalized with `realpath`, and every request holds a
85
+ cross-process lock for that canonical root while it takes bounded regular-file
86
+ snapshots of **both** configs, validates both prospective documents, and
87
+ publishes them. The lock lives in a user-private, repository-external temporary
88
+ directory under a hash of the canonical path, so separate UI processes and
89
+ symlink aliases share one transaction without leaving lock residue in the
90
+ project. The root's canonical path and filesystem identity are revalidated
91
+ before and after snapshots, validation, temporary-file creation, and each
92
+ rename. This deterministically refuses a root or ancestor replacement at every
93
+ available boundary. Node does not expose portable descriptor-relative
94
+ temporary creation or rename, so a same-user process that wins the narrow gap
95
+ between the last identity check and a path-based filesystem call can still
96
+ redirect that call; the endpoint does not claim absolute race closure.
97
+
98
+ For every routed key, persistence first removes the same dot path from its
99
+ non-owner config and then sets it in the owner config. Removal is exact: a root
100
+ removes its descendants, while a descendant removal retains unrelated siblings.
101
+ That reconciliation prevents a stale local override and keeps local-only values
102
+ out of both the committed file and the response. A scalar or array ancestor
103
+ that prevents exact non-owner cleanup is rejected rather than silently retaining
104
+ an overlay shadow. Invalid UTF-8 or recursively duplicated properties in either
105
+ the request or config files, a surgical render whose reparsed structure differs
106
+ from the prospective object, and a changed existing target with no write bit all
107
+ reject before the first publish. Existing and rendered config images share the
108
+ same 128 KiB bound, checked for both targets before either is published.
109
+
110
+ Existing permission modes are restored exactly after the temporary write, even
111
+ when umask would narrow a permissive mode such as `0666`; a new local config is
112
+ still `0600`. Semantic no-ops skip replacement. Each changed file is published
113
+ through a durable atomic replacement after its original bytes are rechecked.
114
+ Filesystems do not offer one atomic rename spanning two files, so an I/O failure
115
+ or an external writer arriving between the two final replacements can still
116
+ leave the first target published and the second unchanged. The endpoint reports
117
+ that failure instead of claiming an all-or-nothing cross-file transaction;
118
+ canonical-root locking prevents silent lost updates among endpoint requests.
119
+
34
120
  ## Live status contract
35
121
 
36
122
  When served by `lisa ui`, the page fetches `GET /api/status` from the same