@codyswann/lisa 4.17.18 → 4.18.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 +4 -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 +8 -2
- 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/package.json +2 -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/typescript/copy-overwrite/scripts/check-skipped-required-checks.mjs +10 -3
- package/ui/README.md +62 -8
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type JsonObject, type JsonValue } from "../sync/json-path.js";
|
|
2
|
+
/** Minimum source image needed for one surgical render. */
|
|
3
|
+
export interface ConfigDocumentSource {
|
|
4
|
+
/** Fixed public filename used only in safe diagnostics. */
|
|
5
|
+
readonly filename: string;
|
|
6
|
+
/** Strict UTF-8 JSON source. */
|
|
7
|
+
readonly text: string;
|
|
8
|
+
/** Semantic source document paired with the text. */
|
|
9
|
+
readonly document: JsonObject;
|
|
10
|
+
}
|
|
11
|
+
/** Fully checked textual and semantic prospective document. */
|
|
12
|
+
export interface RenderedConfigDocument {
|
|
13
|
+
/** Surgical strict-JSON text ready for atomic persistence. */
|
|
14
|
+
readonly text: string;
|
|
15
|
+
/** Reparsing result proven structurally equal to the requested edits. */
|
|
16
|
+
readonly document: JsonObject;
|
|
17
|
+
/** Whether any owner set or non-owner cleanup changed the source. */
|
|
18
|
+
readonly changed: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse one strict, unambiguous object document.
|
|
22
|
+
*
|
|
23
|
+
* `JSON.parse` deliberately accepts duplicate object properties using
|
|
24
|
+
* last-value-wins semantics, while a positional syntax-tree lookup can select
|
|
25
|
+
* an earlier occurrence. Rejecting duplicates prevents those two views from
|
|
26
|
+
* claiming a successful write to different semantic documents.
|
|
27
|
+
* @param text - Strict JSON source or rendered candidate
|
|
28
|
+
* @param filename - Safe fixed filename used in diagnostics
|
|
29
|
+
* @returns Parsed JSON object with exactly one value per property
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseConfigDocument(text: string, filename: string): JsonObject;
|
|
32
|
+
/**
|
|
33
|
+
* Parse strict JSON while refusing recursively duplicated property names.
|
|
34
|
+
*
|
|
35
|
+
* This remains separate from the object-document contract because HTTP input
|
|
36
|
+
* must reject ambiguity before payload shape validation, while preserving the
|
|
37
|
+
* existing shape-specific 400 responses for valid arrays and scalars.
|
|
38
|
+
* @param text - Strict JSON source from a bounded, fatal UTF-8 decode
|
|
39
|
+
* @param filename - Safe fixed label used in diagnostics
|
|
40
|
+
* @returns Parsed JSON value with exactly one value per object property
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseUnambiguousJson(text: string, filename: string): unknown;
|
|
43
|
+
/**
|
|
44
|
+
* Apply owner sets after non-owner removals and prove both representations
|
|
45
|
+
* agree. Ordering is significant for overlapping ancestor/descendant inputs.
|
|
46
|
+
* @param source - Strict source image to edit
|
|
47
|
+
* @param removals - Routed owner paths removed from this non-owner document
|
|
48
|
+
* @param changes - Routed values owned by this document
|
|
49
|
+
* @param exactRemovals - Exact property paths whose segments may contain dots
|
|
50
|
+
* @returns Reparsing-verified prospective document and surgical text
|
|
51
|
+
*/
|
|
52
|
+
export declare function renderConfigChanges(source: ConfigDocumentSource, removals: readonly string[], changes: Readonly<Record<string, JsonValue>>, exactRemovals?: readonly (readonly string[])[]): RenderedConfigDocument;
|
|
53
|
+
//# sourceMappingURL=ui-config-write-document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-config-write-document.d.ts","sourceRoot":"","sources":["../../src/cli/ui-config-write-document.ts"],"names":[],"mappings":"AAQA,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAM9B,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;CAC/B;AAED,+DAA+D;AAC/D,MAAM,WAAW,sBAAsB;IACrC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,UAAU,CAMZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAU5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,oBAAoB,EAC5B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAC5C,aAAa,GAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAO,GACjD,sBAAsB,CAiCxB"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strict, ambiguity-free surgical editing for UI config documents.
|
|
3
|
+
*
|
|
4
|
+
* Strict parsing and the prospective semantic edit stay paired here so the
|
|
5
|
+
* source-relative planner can be checked by reparsing before publication.
|
|
6
|
+
* @module cli/ui-config-write-document
|
|
7
|
+
*/
|
|
8
|
+
import { applyEdits, parseTree } from "jsonc-parser";
|
|
9
|
+
import { getAtPropertyPath, isJsonObject, jsonEquals, } from "../sync/json-path.js";
|
|
10
|
+
import { planConfigTextEdits, } from "./ui-config-write-patch-plan.js";
|
|
11
|
+
/**
|
|
12
|
+
* Parse one strict, unambiguous object document.
|
|
13
|
+
*
|
|
14
|
+
* `JSON.parse` deliberately accepts duplicate object properties using
|
|
15
|
+
* last-value-wins semantics, while a positional syntax-tree lookup can select
|
|
16
|
+
* an earlier occurrence. Rejecting duplicates prevents those two views from
|
|
17
|
+
* claiming a successful write to different semantic documents.
|
|
18
|
+
* @param text - Strict JSON source or rendered candidate
|
|
19
|
+
* @param filename - Safe fixed filename used in diagnostics
|
|
20
|
+
* @returns Parsed JSON object with exactly one value per property
|
|
21
|
+
*/
|
|
22
|
+
export function parseConfigDocument(text, filename) {
|
|
23
|
+
const parsed = parseUnambiguousJson(text, filename);
|
|
24
|
+
if (!isJsonObject(parsed)) {
|
|
25
|
+
throw new Error(`${filename} must contain a JSON object`);
|
|
26
|
+
}
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parse strict JSON while refusing recursively duplicated property names.
|
|
31
|
+
*
|
|
32
|
+
* This remains separate from the object-document contract because HTTP input
|
|
33
|
+
* must reject ambiguity before payload shape validation, while preserving the
|
|
34
|
+
* existing shape-specific 400 responses for valid arrays and scalars.
|
|
35
|
+
* @param text - Strict JSON source from a bounded, fatal UTF-8 decode
|
|
36
|
+
* @param filename - Safe fixed label used in diagnostics
|
|
37
|
+
* @returns Parsed JSON value with exactly one value per object property
|
|
38
|
+
*/
|
|
39
|
+
export function parseUnambiguousJson(text, filename) {
|
|
40
|
+
const parsed = JSON.parse(text);
|
|
41
|
+
const tree = parseTree(text, [], {
|
|
42
|
+
allowTrailingComma: false,
|
|
43
|
+
disallowComments: true,
|
|
44
|
+
});
|
|
45
|
+
if (tree === undefined || hasDuplicateObjectKey(tree)) {
|
|
46
|
+
throw new Error(`${filename} contains duplicate object keys`);
|
|
47
|
+
}
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Apply owner sets after non-owner removals and prove both representations
|
|
52
|
+
* agree. Ordering is significant for overlapping ancestor/descendant inputs.
|
|
53
|
+
* @param source - Strict source image to edit
|
|
54
|
+
* @param removals - Routed owner paths removed from this non-owner document
|
|
55
|
+
* @param changes - Routed values owned by this document
|
|
56
|
+
* @param exactRemovals - Exact property paths whose segments may contain dots
|
|
57
|
+
* @returns Reparsing-verified prospective document and surgical text
|
|
58
|
+
*/
|
|
59
|
+
export function renderConfigChanges(source, removals, changes, exactRemovals = []) {
|
|
60
|
+
const edits = [
|
|
61
|
+
...removals.map(key => ({ kind: "remove", path: key.split(".") })),
|
|
62
|
+
...exactRemovals.map(path => ({ kind: "remove", path })),
|
|
63
|
+
...Object.entries(changes).map(([key, value]) => ({ kind: "set", path: key.split("."), value })),
|
|
64
|
+
];
|
|
65
|
+
const prospective = edits.reduce((state, edit) => applySemanticEdit(state, edit), {
|
|
66
|
+
document: source.document,
|
|
67
|
+
changed: false,
|
|
68
|
+
touched: [],
|
|
69
|
+
});
|
|
70
|
+
if (!prospective.changed) {
|
|
71
|
+
return { text: source.text, document: source.document, changed: false };
|
|
72
|
+
}
|
|
73
|
+
const tree = requireConfigTree(source.text, source.filename);
|
|
74
|
+
const textEdits = planConfigTextEdits(source.text, tree, source.document, prospective.document, prospective.touched);
|
|
75
|
+
const renderedText = applyEdits(source.text, [...textEdits]);
|
|
76
|
+
const reparsed = parseConfigDocument(renderedText, source.filename);
|
|
77
|
+
if (!jsonEquals(reparsed, prospective.document)) {
|
|
78
|
+
throw new Error(`${source.filename} surgical edit was ambiguous`);
|
|
79
|
+
}
|
|
80
|
+
return { text: renderedText, document: reparsed, changed: true };
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Detect ambiguity recursively because a changed path may sit below a duplicate
|
|
84
|
+
* ancestor even when its own final property appears only once.
|
|
85
|
+
* @param node - Strict JSON syntax tree node
|
|
86
|
+
* @returns Whether any object contains the same property more than once
|
|
87
|
+
*/
|
|
88
|
+
function hasDuplicateObjectKey(node) {
|
|
89
|
+
if (node.type === "object") {
|
|
90
|
+
const keys = (node.children ?? [])
|
|
91
|
+
.map(property => property.children?.[0]?.value)
|
|
92
|
+
.filter((key) => typeof key === "string");
|
|
93
|
+
if (new Set(keys).size !== keys.length) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return (node.children ?? []).some(hasDuplicateObjectKey);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Apply one edit to the prospective object before planning source ranges.
|
|
101
|
+
* @param state - Semantic result accumulated from earlier ordered edits
|
|
102
|
+
* @param edit - Owner set or non-owner removal
|
|
103
|
+
* @returns Prospective state plus only the edits that changed semantics
|
|
104
|
+
*/
|
|
105
|
+
function applySemanticEdit(state, edit) {
|
|
106
|
+
if (edit.kind === "remove") {
|
|
107
|
+
assertRemovalPathIsReachable(state.document, edit.path);
|
|
108
|
+
}
|
|
109
|
+
const current = getAtPropertyPath(state.document, edit.path);
|
|
110
|
+
if ((edit.kind === "remove" && current === undefined) ||
|
|
111
|
+
(edit.kind === "set" && jsonEquals(current, edit.value))) {
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
document: edit.kind === "remove"
|
|
116
|
+
? removeAtPropertyPath(state.document, edit.path)
|
|
117
|
+
: setAtPropertyPath(state.document, edit.path, edit.value),
|
|
118
|
+
changed: true,
|
|
119
|
+
touched: [...state.touched, edit],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Reparse the already validated source into the positional tree used for edits.
|
|
124
|
+
* @param text - Original strict JSON bytes decoded as text
|
|
125
|
+
* @param filename - Safe fixed filename used in diagnostics
|
|
126
|
+
* @returns Root object node whose offsets all refer to the original text
|
|
127
|
+
*/
|
|
128
|
+
function requireConfigTree(text, filename) {
|
|
129
|
+
const tree = parseTree(text, [], {
|
|
130
|
+
allowTrailingComma: false,
|
|
131
|
+
disallowComments: true,
|
|
132
|
+
});
|
|
133
|
+
if (tree?.type !== "object") {
|
|
134
|
+
throw new Error(`${filename} must contain a JSON object`);
|
|
135
|
+
}
|
|
136
|
+
return tree;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Refuse descendant cleanup when a scalar or array ancestor shadows its owner.
|
|
140
|
+
* Deleting that ancestor would also delete data outside the routed path, while
|
|
141
|
+
* treating the cleanup as a no-op would leave overlay precedence unchanged.
|
|
142
|
+
* @param root - Non-owner document being reconciled
|
|
143
|
+
* @param propertyPath - Exact routed owner path that must become absent here
|
|
144
|
+
*/
|
|
145
|
+
function assertRemovalPathIsReachable(root, propertyPath) {
|
|
146
|
+
const ancestors = propertyPath.slice(0, -1);
|
|
147
|
+
assertObjectAncestors(root, ancestors);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Walk only present ancestors: an absent branch cannot shadow anything, while
|
|
151
|
+
* every present branch must remain an object for exact descendant removal.
|
|
152
|
+
* @param node - Present object at the current path depth
|
|
153
|
+
* @param segments - Remaining ancestor segments before the routed leaf
|
|
154
|
+
*/
|
|
155
|
+
function assertObjectAncestors(node, segments) {
|
|
156
|
+
const [head, ...rest] = segments;
|
|
157
|
+
if (head === undefined)
|
|
158
|
+
return;
|
|
159
|
+
const child = node[head];
|
|
160
|
+
if (child === undefined)
|
|
161
|
+
return;
|
|
162
|
+
if (!isJsonObject(child)) {
|
|
163
|
+
throw new Error("Config owner cleanup is blocked by a non-object ancestor");
|
|
164
|
+
}
|
|
165
|
+
assertObjectAncestors(child, rest);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Remove exactly one property path while retaining every ancestor and sibling.
|
|
169
|
+
* @param root - Prospective object to copy
|
|
170
|
+
* @param propertyPath - Exact path being removed from the non-owner document
|
|
171
|
+
* @returns Object without that path and with unrelated siblings intact
|
|
172
|
+
*/
|
|
173
|
+
function removeAtPropertyPath(root, propertyPath) {
|
|
174
|
+
const [head, ...rest] = propertyPath;
|
|
175
|
+
if (head === undefined) {
|
|
176
|
+
throw new Error("Config root removal is not writable");
|
|
177
|
+
}
|
|
178
|
+
if (rest.length === 0) {
|
|
179
|
+
const { [head]: _removed, ...remaining } = root;
|
|
180
|
+
return remaining;
|
|
181
|
+
}
|
|
182
|
+
const child = root[head];
|
|
183
|
+
if (!isJsonObject(child)) {
|
|
184
|
+
return root;
|
|
185
|
+
}
|
|
186
|
+
return { ...root, [head]: removeAtPropertyPath(child, rest) };
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Immutably set an exact property path, creating missing object ancestors.
|
|
190
|
+
* @param root - Object to copy
|
|
191
|
+
* @param propertyPath - Exact decoded property names
|
|
192
|
+
* @param value - JSON value to write
|
|
193
|
+
* @returns Updated object
|
|
194
|
+
*/
|
|
195
|
+
function setAtPropertyPath(root, propertyPath, value) {
|
|
196
|
+
const [head, ...rest] = propertyPath;
|
|
197
|
+
if (head === undefined) {
|
|
198
|
+
if (!isJsonObject(value)) {
|
|
199
|
+
throw new Error("Config root replacement requires an object value");
|
|
200
|
+
}
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
if (rest.length === 0) {
|
|
204
|
+
return { ...root, [head]: value };
|
|
205
|
+
}
|
|
206
|
+
const child = root[head];
|
|
207
|
+
return {
|
|
208
|
+
...root,
|
|
209
|
+
[head]: setAtPropertyPath(isJsonObject(child) ? child : {}, rest, value),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=ui-config-write-document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-config-write-document.js","sourceRoot":"","sources":["../../src/cli/ui-config-write-document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ui-config-write-patch-plan.ts
|
|
3
|
+
* @description Deterministic non-overlapping patch planning for UI config JSON.
|
|
4
|
+
* @module cli/ui-config-write-patch-plan
|
|
5
|
+
*/
|
|
6
|
+
import { type Edit as JsonTextEdit, type Node as JsonNode } from "jsonc-parser";
|
|
7
|
+
import { type JsonObject, type JsonValue } from "../sync/json-path.js";
|
|
8
|
+
/** One requested semantic mutation in endpoint order. */
|
|
9
|
+
export type ConfigDocumentEdit = {
|
|
10
|
+
readonly kind: "remove";
|
|
11
|
+
readonly path: readonly string[];
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "set";
|
|
14
|
+
readonly path: readonly string[];
|
|
15
|
+
readonly value: JsonValue;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Plan every changed path against one immutable original syntax tree.
|
|
19
|
+
*
|
|
20
|
+
* Missing descendants collapse to the first absent/non-object branch, so a
|
|
21
|
+
* formatter never needs to borrow and replace an unrelated sibling for context.
|
|
22
|
+
* @param text - Original strict JSON text
|
|
23
|
+
* @param tree - Original syntax tree whose offsets refer to `text`
|
|
24
|
+
* @param source - Original semantic document
|
|
25
|
+
* @param prospective - Final semantic document after ordered edits
|
|
26
|
+
* @param touched - Ordered edits that changed semantics
|
|
27
|
+
* @returns Deterministic non-overlapping original-offset text edits
|
|
28
|
+
*/
|
|
29
|
+
export declare function planConfigTextEdits(text: string, tree: JsonNode, source: JsonObject, prospective: JsonObject, touched: readonly ConfigDocumentEdit[]): readonly JsonTextEdit[];
|
|
30
|
+
//# sourceMappingURL=ui-config-write-patch-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-config-write-patch-plan.d.ts","sourceRoot":"","sources":["../../src/cli/ui-config-write-patch-plan.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAEL,KAAK,IAAI,IAAI,YAAY,EACzB,KAAK,IAAI,IAAI,QAAQ,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAQ9B,yDAAyD;AACzD,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC7D;IACE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B,CAAC;AAEN;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,UAAU,EACvB,OAAO,EAAE,SAAS,kBAAkB,EAAE,GACrC,SAAS,YAAY,EAAE,CAazB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ui-config-write-patch-plan.ts
|
|
3
|
+
* @description Deterministic non-overlapping patch planning for UI config JSON.
|
|
4
|
+
* @module cli/ui-config-write-patch-plan
|
|
5
|
+
*/
|
|
6
|
+
import { findNodeAtLocation, } from "jsonc-parser";
|
|
7
|
+
import { getAtPropertyPath, isJsonObject, } from "../sync/json-path.js";
|
|
8
|
+
import { planObjectPatchEdits, serializeConfigValue, } from "./ui-config-write-property-edits.js";
|
|
9
|
+
/**
|
|
10
|
+
* Plan every changed path against one immutable original syntax tree.
|
|
11
|
+
*
|
|
12
|
+
* Missing descendants collapse to the first absent/non-object branch, so a
|
|
13
|
+
* formatter never needs to borrow and replace an unrelated sibling for context.
|
|
14
|
+
* @param text - Original strict JSON text
|
|
15
|
+
* @param tree - Original syntax tree whose offsets refer to `text`
|
|
16
|
+
* @param source - Original semantic document
|
|
17
|
+
* @param prospective - Final semantic document after ordered edits
|
|
18
|
+
* @param touched - Ordered edits that changed semantics
|
|
19
|
+
* @returns Deterministic non-overlapping original-offset text edits
|
|
20
|
+
*/
|
|
21
|
+
export function planConfigTextEdits(text, tree, source, prospective, touched) {
|
|
22
|
+
const patches = collapseConfigPatches(source, prospective, touched);
|
|
23
|
+
const planned = patches.reduce((plan, patch) => planConfigPatch(tree, plan, patch), {
|
|
24
|
+
replacements: [],
|
|
25
|
+
groups: [],
|
|
26
|
+
});
|
|
27
|
+
return [
|
|
28
|
+
...planned.replacements,
|
|
29
|
+
...planned.groups.flatMap(group => planObjectPatchEdits(text, tree, group)),
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Collapse overlapping changes to the shallowest original source property.
|
|
34
|
+
* @param source - Original semantic document
|
|
35
|
+
* @param prospective - Final semantic document after ordered edits
|
|
36
|
+
* @param touched - Ordered edits that actually changed semantics
|
|
37
|
+
* @returns Stable property patches with no ancestor/descendant overlap
|
|
38
|
+
*/
|
|
39
|
+
function collapseConfigPatches(source, prospective, touched) {
|
|
40
|
+
const candidates = touched.map((edit, order) => {
|
|
41
|
+
const requestedPath = edit.path;
|
|
42
|
+
const path = edit.kind === "remove"
|
|
43
|
+
? requestedPath
|
|
44
|
+
: findSetPatchPath(source, requestedPath);
|
|
45
|
+
return { path, value: getAtPropertyPath(prospective, path), order };
|
|
46
|
+
});
|
|
47
|
+
const collapsed = [...candidates]
|
|
48
|
+
.sort((left, right) => left.path.length - right.path.length || left.order - right.order)
|
|
49
|
+
.reduce((patches, candidate) => {
|
|
50
|
+
return patches.some(patch => isPathPrefix(patch.path, candidate.path))
|
|
51
|
+
? patches
|
|
52
|
+
: [...patches, candidate];
|
|
53
|
+
}, []);
|
|
54
|
+
return [...collapsed].sort((left, right) => left.order - right.order);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Find the shallowest property whose replacement can express a set operation.
|
|
58
|
+
* @param node - Original value at the current path depth
|
|
59
|
+
* @param segments - Remaining requested dot-path segments
|
|
60
|
+
* @param prefix - Original path already proven to contain objects
|
|
61
|
+
* @returns Existing leaf or first missing/non-object branch to replace
|
|
62
|
+
*/
|
|
63
|
+
function findSetPatchPath(node, segments, prefix = []) {
|
|
64
|
+
const [head, ...rest] = segments;
|
|
65
|
+
if (head === undefined)
|
|
66
|
+
return prefix;
|
|
67
|
+
const path = [...prefix, head];
|
|
68
|
+
if (rest.length === 0)
|
|
69
|
+
return path;
|
|
70
|
+
const child = node[head];
|
|
71
|
+
return isJsonObject(child) ? findSetPatchPath(child, rest, path) : path;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compare dot paths without joining them into ambiguous strings.
|
|
75
|
+
* @param prefix - Candidate ancestor path
|
|
76
|
+
* @param candidate - Candidate descendant path
|
|
77
|
+
* @returns Whether every prefix segment matches the candidate
|
|
78
|
+
*/
|
|
79
|
+
function isPathPrefix(prefix, candidate) {
|
|
80
|
+
return (prefix.length <= candidate.length &&
|
|
81
|
+
prefix.every((segment, index) => candidate[index] === segment));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Plan one patch as an existing value replacement or grouped child mutation.
|
|
85
|
+
* @param tree - Original strict-JSON syntax tree
|
|
86
|
+
* @param plan - Replacements and object groups accumulated so far
|
|
87
|
+
* @param plan.replacements - Existing-value edits accumulated so far
|
|
88
|
+
* @param plan.groups - Direct object-child mutations accumulated so far
|
|
89
|
+
* @param patch - Collapsed semantic patch
|
|
90
|
+
* @returns Plan including this patch
|
|
91
|
+
*/
|
|
92
|
+
function planConfigPatch(tree, plan, patch) {
|
|
93
|
+
const valueNode = findNodeAtLocation(tree, [...patch.path]);
|
|
94
|
+
if (valueNode !== undefined && patch.value !== undefined) {
|
|
95
|
+
return {
|
|
96
|
+
...plan,
|
|
97
|
+
replacements: [
|
|
98
|
+
...plan.replacements,
|
|
99
|
+
{
|
|
100
|
+
offset: valueNode.offset,
|
|
101
|
+
length: valueNode.length,
|
|
102
|
+
content: serializeConfigValue(patch.value),
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const parentPath = patch.path.slice(0, -1);
|
|
108
|
+
const key = patch.path.at(-1);
|
|
109
|
+
if (key === undefined) {
|
|
110
|
+
throw new Error("Config root replacement is not writable");
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
...plan,
|
|
114
|
+
groups: addObjectPatch(plan.groups, parentPath, key, patch, valueNode !== undefined),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Add one insertion or removal to an immutable parent-object group.
|
|
119
|
+
* @param groups - Groups accumulated for earlier patches
|
|
120
|
+
* @param parentPath - Original object that owns the direct property
|
|
121
|
+
* @param key - Direct property name
|
|
122
|
+
* @param patch - Final insertion value and stable request order
|
|
123
|
+
* @param removesExisting - Whether the original tree contains this property
|
|
124
|
+
* @returns Groups including this mutation
|
|
125
|
+
*/
|
|
126
|
+
function addObjectPatch(groups, parentPath, key, patch, removesExisting) {
|
|
127
|
+
const existing = groups.find(group => pathsEqual(group.parentPath, parentPath));
|
|
128
|
+
const next = {
|
|
129
|
+
parentPath,
|
|
130
|
+
removals: removesExisting
|
|
131
|
+
? [...(existing?.removals ?? []), key]
|
|
132
|
+
: (existing?.removals ?? []),
|
|
133
|
+
insertions: removesExisting
|
|
134
|
+
? (existing?.insertions ?? [])
|
|
135
|
+
: [...(existing?.insertions ?? []), patch],
|
|
136
|
+
};
|
|
137
|
+
return existing === undefined
|
|
138
|
+
? [...groups, next]
|
|
139
|
+
: groups.map(group => pathsEqual(group.parentPath, parentPath) ? next : group);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Compare two syntax-tree paths exactly.
|
|
143
|
+
* @param left - First path
|
|
144
|
+
* @param right - Second path
|
|
145
|
+
* @returns Whether both contain the same segments in the same order
|
|
146
|
+
*/
|
|
147
|
+
function pathsEqual(left, right) {
|
|
148
|
+
return (left.length === right.length &&
|
|
149
|
+
left.every((segment, index) => right[index] === segment));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=ui-config-write-patch-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-config-write-patch-plan.js","sourceRoot":"","sources":["../../src/cli/ui-config-write-patch-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from "../sync/json-path.js";
|
|
2
|
+
/** Changes already classified at the request boundary, before any file I/O. */
|
|
3
|
+
export interface RoutedConfigChanges {
|
|
4
|
+
/** Registry-root or registry-descendant changes for committed governance. */
|
|
5
|
+
readonly committed: Readonly<Record<string, JsonValue>>;
|
|
6
|
+
/** Exact console-authorized changes for the gitignored developer overlay. */
|
|
7
|
+
readonly local: Readonly<Record<string, JsonValue>>;
|
|
8
|
+
}
|
|
9
|
+
/** Callback that enforces registry validators against the prospective config. */
|
|
10
|
+
export type ValidateCommittedConfig = (config: JsonObject) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Persist one pre-classified request under the project write queue.
|
|
13
|
+
* @param destDir - Project root containing the two fixed config filenames
|
|
14
|
+
* @param changes - Changes split by committed versus local ownership
|
|
15
|
+
* @param validateCommitted - Registry validation applied before either write
|
|
16
|
+
* @returns Prospective committed config only; local values are never echoed
|
|
17
|
+
*/
|
|
18
|
+
export declare function persistRoutedConfigChanges(destDir: string, changes: RoutedConfigChanges, validateCommitted: ValidateCommittedConfig): Promise<JsonObject>;
|
|
19
|
+
//# sourceMappingURL=ui-config-write-persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-config-write-persistence.d.ts","sourceRoot":"","sources":["../../src/cli/ui-config-write-persistence.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AA0BlE,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACxD,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACrD;AAoBD,iFAAiF;AACjF,MAAM,MAAM,uBAAuB,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,mBAAmB,EAC5B,iBAAiB,EAAE,uBAAuB,GACzC,OAAO,CAAC,UAAU,CAAC,CAwCrB"}
|