@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.
- package/dist/cli/ui-config-write-document.d.ts +53 -0
- package/dist/cli/ui-config-write-document.d.ts.map +1 -0
- package/dist/cli/ui-config-write-document.js +212 -0
- package/dist/cli/ui-config-write-document.js.map +1 -0
- package/dist/cli/ui-config-write-patch-plan.d.ts +30 -0
- package/dist/cli/ui-config-write-patch-plan.d.ts.map +1 -0
- package/dist/cli/ui-config-write-patch-plan.js +151 -0
- package/dist/cli/ui-config-write-patch-plan.js.map +1 -0
- package/dist/cli/ui-config-write-persistence.d.ts +19 -0
- package/dist/cli/ui-config-write-persistence.d.ts.map +1 -0
- package/dist/cli/ui-config-write-persistence.js +294 -0
- package/dist/cli/ui-config-write-persistence.js.map +1 -0
- package/dist/cli/ui-config-write-property-edits.d.ts +40 -0
- package/dist/cli/ui-config-write-property-edits.d.ts.map +1 -0
- package/dist/cli/ui-config-write-property-edits.js +250 -0
- package/dist/cli/ui-config-write-property-edits.js.map +1 -0
- package/dist/cli/ui-config-write-provenance.d.ts +12 -0
- package/dist/cli/ui-config-write-provenance.d.ts.map +1 -0
- package/dist/cli/ui-config-write-provenance.js +29 -0
- package/dist/cli/ui-config-write-provenance.js.map +1 -0
- package/dist/cli/ui-config-write-root-identity.d.ts +25 -0
- package/dist/cli/ui-config-write-root-identity.d.ts.map +1 -0
- package/dist/cli/ui-config-write-root-identity.js +66 -0
- package/dist/cli/ui-config-write-root-identity.js.map +1 -0
- package/dist/cli/ui-config-write.d.ts.map +1 -1
- package/dist/cli/ui-config-write.js +47 -92
- package/dist/cli/ui-config-write.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +14 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +21 -5
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/sync/json-path.d.ts +10 -0
- package/dist/sync/json-path.d.ts.map +1 -1
- package/dist/sync/json-path.js +14 -0
- package/dist/sync/json-path.js.map +1 -1
- package/dist/sync/sync-population.d.ts +6 -0
- package/dist/sync/sync-population.d.ts.map +1 -1
- package/dist/sync/sync-population.js +8 -0
- package/dist/sync/sync-population.js.map +1 -1
- package/dist/utils/atomic-file-write.d.ts +5 -4
- package/dist/utils/atomic-file-write.d.ts.map +1 -1
- package/dist/utils/atomic-file-write.js +3 -0
- package/dist/utils/atomic-file-write.js.map +1 -1
- package/expo/copy-overwrite/scripts/bdd/baseline.mjs +10 -2
- package/expo/copy-overwrite/scripts/bdd/render.mjs +3 -2
- package/expo/copy-overwrite/scripts/bdd-matrix.mjs +3 -3
- package/package.json +7 -2
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/scripts/check-ui-demo-data.mjs +102 -0
- package/ui/README.md +94 -8
- package/ui/index.html +901 -115
|
@@ -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:**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|