@daweifu/capability-menu 0.1.1 → 0.1.3

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 (44) hide show
  1. package/README.en.md +238 -0
  2. package/README.md +127 -63
  3. package/cordis.patch.yml +37 -46
  4. package/lib/client.d.ts +224 -19
  5. package/lib/client.d.ts.map +1 -1
  6. package/lib/client.js +1796 -226
  7. package/lib/constants.js +33 -0
  8. package/lib/constants.js.map +1 -0
  9. package/lib/index.js +1 -1
  10. package/lib/invoke.js +68 -96
  11. package/lib/invoke.js.map +1 -1
  12. package/lib/locations.js +541 -0
  13. package/lib/locations.js.map +1 -0
  14. package/lib/patch-file.js +192 -0
  15. package/lib/patch-file.js.map +1 -0
  16. package/lib/policy.js +422 -94
  17. package/lib/policy.js.map +1 -1
  18. package/lib/registry.js +410 -152
  19. package/lib/registry.js.map +1 -1
  20. package/lib/search.js +26 -9
  21. package/lib/search.js.map +1 -1
  22. package/lib/server/remote.js +219 -3
  23. package/lib/server/remote.js.map +1 -1
  24. package/lib/types/constants.d.ts +33 -0
  25. package/lib/types/constants.d.ts.map +1 -0
  26. package/lib/types/index.d.ts +1 -1
  27. package/lib/types/invoke.d.ts +7 -13
  28. package/lib/types/invoke.d.ts.map +1 -1
  29. package/lib/types/locations.d.ts +142 -0
  30. package/lib/types/locations.d.ts.map +1 -0
  31. package/lib/types/patch-file.d.ts +46 -0
  32. package/lib/types/patch-file.d.ts.map +1 -0
  33. package/lib/types/policy.d.ts +115 -53
  34. package/lib/types/policy.d.ts.map +1 -1
  35. package/lib/types/registry.d.ts +94 -25
  36. package/lib/types/registry.d.ts.map +1 -1
  37. package/lib/types/search.d.ts.map +1 -1
  38. package/lib/types/server/remote.d.ts +68 -2
  39. package/lib/types/server/remote.d.ts.map +1 -1
  40. package/package.json +23 -26
  41. package/lib/invariant.js +0 -22
  42. package/lib/invariant.js.map +0 -1
  43. package/lib/types/invariant.d.ts +0 -16
  44. package/lib/types/invariant.d.ts.map +0 -1
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Comment-preserving, loop-safe editing of a dsh patch file.
3
+ *
4
+ * dsh owns and composes these files (`~/.dsh/cordis.patch.yml` and per-profile
5
+ * `cordis.patch.yml`), and in a `patchReload: live` profile it *watches* them:
6
+ * any write triggers a transactional re-apply of the patch, which re-applies
7
+ * this very plugin. Two consequences drive everything below:
8
+ *
9
+ * - **A no-op must never write.** Writing on every startup/apply would make the
10
+ * plugin reload itself forever. So each mutation reports whether it actually
11
+ * changed the document, and nothing is written when it did not.
12
+ * - **A write must never damage the file.** The file is a hand-maintained asset
13
+ * (comments, `!!js` expressions, credentials). Edits go through `yaml`'s
14
+ * document API, which keeps comments, and every write is backed up, verified
15
+ * by re-parsing, and rolled back on failure.
16
+ *
17
+ * Note the round-trip is *not* byte-identical — `yaml` normalizes trailing
18
+ * comment spacing and quoting style. That is why "did this change anything?" is
19
+ * decided by the mutation, never by comparing before/after text.
20
+ */
21
+ import { copyFile, readFile, rename, unlink, writeFile } from 'node:fs/promises';
22
+ import { randomUUID } from 'node:crypto';
23
+ import { homedir } from 'node:os';
24
+ import { join } from 'node:path';
25
+ import YAML from 'yaml';
26
+ /** Default patch file: the home-level layer shared by every profile. */
27
+ export function defaultPatchFile() {
28
+ const home = process.env['DSH_HOME'];
29
+ if (home !== undefined && home.length > 0)
30
+ return join(home, 'cordis.patch.yml');
31
+ return join(homedir(), '.dsh', 'cordis.patch.yml');
32
+ }
33
+ /**
34
+ * Every entry row in the document: both bare top-level rows and rows nested in
35
+ * an `- insert:` block (the form dsh's own patches and this bundle use).
36
+ */
37
+ function* entryNodes(doc) {
38
+ const root = doc.contents;
39
+ if (!YAML.isSeq(root))
40
+ return;
41
+ for (const item of root.items) {
42
+ if (!YAML.isMap(item))
43
+ continue;
44
+ const insert = item.get('insert');
45
+ if (insert !== undefined && insert !== null) {
46
+ if (!YAML.isSeq(insert))
47
+ continue;
48
+ for (const row of insert.items) {
49
+ if (YAML.isMap(row))
50
+ yield { node: row, parent: insert };
51
+ }
52
+ continue;
53
+ }
54
+ if (item.get('id') !== undefined)
55
+ yield { node: item, parent: root };
56
+ }
57
+ }
58
+ /** Find the entry row with `id`, if the file declares one. */
59
+ export function findEntry(doc, id) {
60
+ for (const { node } of entryNodes(doc)) {
61
+ if (node.get('id') === id)
62
+ return node;
63
+ }
64
+ return undefined;
65
+ }
66
+ /** Read every declared entry as plain data (never mutates the file). */
67
+ export async function readEntries(file) {
68
+ const source = await readFile(file, 'utf8');
69
+ const doc = YAML.parseDocument(source);
70
+ const entries = [];
71
+ for (const { node } of entryNodes(doc)) {
72
+ const value = node.toJSON();
73
+ if (typeof value.id !== 'string' || typeof value.name !== 'string')
74
+ continue;
75
+ entries.push(value);
76
+ }
77
+ return entries;
78
+ }
79
+ /** The last `- insert:` block in the document, if any. */
80
+ function lastInsertSeq(doc) {
81
+ const root = doc.contents;
82
+ if (!YAML.isSeq(root))
83
+ return undefined;
84
+ let found;
85
+ for (const item of root.items) {
86
+ if (!YAML.isMap(item))
87
+ continue;
88
+ const insert = item.get('insert');
89
+ if (YAML.isSeq(insert))
90
+ found = insert;
91
+ }
92
+ return found;
93
+ }
94
+ /**
95
+ * Append a row to the document. Reuses the last `- insert:` block so new rows
96
+ * land next to the existing ones; creates one when the file has none.
97
+ */
98
+ export function addEntry(doc, entry) {
99
+ const root = doc.contents;
100
+ if (!YAML.isSeq(root))
101
+ throw new Error('patch file root is not a sequence');
102
+ const target = lastInsertSeq(doc) ?? (() => {
103
+ const block = doc.createNode({ insert: [] });
104
+ // `root` is narrowed to a parsed sequence; the freshly built map is not
105
+ // narrowed with it even though it is a real document node.
106
+ root.add(block);
107
+ return block.get('insert');
108
+ })();
109
+ target.add(doc.createNode({ ...entry }));
110
+ }
111
+ /**
112
+ * Append a bare, id-targeted override row (`- id: … / name: … / config: …`) at
113
+ * the top level — a patch that *finds* a row instead of adding one.
114
+ *
115
+ * Deliberately not {@link addEntry}: the row being configured is usually
116
+ * contributed by another layer. This plugin's own bundle patch inserts
117
+ * `capability-menu-policy`, and a profile's home layer is applied *after* that
118
+ * layer, so inserting a second row with the same id here leaves the composed
119
+ * tree with two rows sharing an id — which dsh refuses outright with
120
+ * `duplicate loader entry id`, taking the whole profile down.
121
+ */
122
+ export function addEntryOverride(doc, entry) {
123
+ const root = doc.contents;
124
+ if (!YAML.isSeq(root))
125
+ throw new Error('patch file root is not a sequence');
126
+ // `root` is narrowed to a parsed sequence; the freshly built map is not
127
+ // narrowed with it even though it is a real document node.
128
+ root.add(doc.createNode({ ...entry }));
129
+ }
130
+ /** Remove the row with `id`. Returns false when the file has no such row. */
131
+ export function removeEntry(doc, id) {
132
+ for (const { node, parent } of entryNodes(doc)) {
133
+ if (node.get('id') !== id)
134
+ continue;
135
+ parent.delete(parent.items.indexOf(node));
136
+ return true;
137
+ }
138
+ return false;
139
+ }
140
+ /** Set or clear `disabled:` on the row with `id`. */
141
+ export function setEntryDisabled(doc, id, disabled) {
142
+ const node = findEntry(doc, id);
143
+ if (node === undefined)
144
+ return false;
145
+ if (disabled)
146
+ node.set('disabled', true);
147
+ else
148
+ node.delete('disabled');
149
+ return true;
150
+ }
151
+ /** Replace the row's `config:` (patch semantics replace the whole value). */
152
+ export function setEntryConfig(doc, id, config) {
153
+ const node = findEntry(doc, id);
154
+ if (node === undefined)
155
+ return false;
156
+ node.set('config', doc.createNode(config));
157
+ return true;
158
+ }
159
+ /**
160
+ * Load the patch file, apply `mutate`, and persist only when it reports a
161
+ * change. Returns whether a write happened (i.e. whether dsh will hot-reload).
162
+ *
163
+ * `mutate` must be pure apart from its edits to `doc`: it may be the only
164
+ * chance to change the file, and a thrown error leaves the file untouched.
165
+ */
166
+ export async function mutatePatch(file, mutate) {
167
+ const original = await readFile(file, 'utf8');
168
+ const doc = YAML.parseDocument(original);
169
+ if (!mutate(doc))
170
+ return false;
171
+ const next = doc.toString();
172
+ const backup = `${file}.bak`;
173
+ const tmp = `${file}.tmp-${randomUUID()}`;
174
+ await copyFile(file, backup);
175
+ try {
176
+ await writeFile(tmp, next, 'utf8');
177
+ // Verify before it becomes the live file: a document that no longer parses
178
+ // would take the whole profile down on the next reload.
179
+ const check = YAML.parseDocument(await readFile(tmp, 'utf8'));
180
+ if (check.errors.length > 0) {
181
+ throw new Error(`rewritten patch file does not parse: ${check.errors[0]?.message ?? 'unknown error'}`);
182
+ }
183
+ await rename(tmp, file);
184
+ return true;
185
+ }
186
+ catch (error) {
187
+ await unlink(tmp).catch(() => { });
188
+ await copyFile(backup, file).catch(() => { });
189
+ throw error;
190
+ }
191
+ }
192
+ //# sourceMappingURL=patch-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-file.js","sourceRoot":"","sources":["../src/patch-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,IAAI,MAAM,MAAM,CAAA;AAUvB,wEAAwE;AACxE,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACpC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;IAChF,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAA;AACpD,CAAC;AAED;;;GAGG;AACH,QAAQ,CAAC,CAAC,UAAU,CAAC,GAAyB;IAC5C,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;IACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAM;IAC7B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACjC,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;gBAAE,SAAQ;YACjC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBAC/B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;oBAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;YAC1D,CAAC;YACD,SAAQ;QACV,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACtE,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,GAAyB,EAAE,EAAU;IAC7D,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAA;IACxC,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAY;IAC5C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,MAAM,OAAO,GAAiB,EAAE,CAAA;IAChC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAyB,CAAA;QAClD,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,SAAQ;QAC5E,OAAO,CAAC,IAAI,CAAC,KAAmB,CAAC,CAAA;IACnC,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,0DAA0D;AAC1D,SAAS,aAAa,CAAC,GAAyB;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;IACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IACvC,IAAI,KAA+B,CAAA;IACnC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAQ;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QACjC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;YAAE,KAAK,GAAG,MAAM,CAAA;IACxC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAyB,EAAE,KAAiB;IACnE,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;IACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAC3E,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,GAAiB,EAAE;QACvD,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAiB,CAAA;QAC5D,wEAAwE;QACxE,2DAA2D;QAC3D,IAAI,CAAC,GAAG,CAAC,KAAmC,CAAC,CAAA;QAC7C,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAiB,CAAA;IAC5C,CAAC,CAAC,EAAE,CAAA;IACJ,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAyB,EAAE,KAAiB;IAC3E,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAA;IACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAC3E,wEAAwE;IACxE,2DAA2D;IAC3D,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,GAAG,KAAK,EAAE,CAA+B,CAAC,CAAA;AACtE,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,GAAyB,EAAE,EAAU;IAC/D,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE;YAAE,SAAQ;QACnC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;QACzC,OAAO,IAAI,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,gBAAgB,CAAC,GAAyB,EAAE,EAAU,EAAE,QAAiB;IACvF,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC/B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACpC,IAAI,QAAQ;QAAE,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;;QACnC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IAC5B,OAAO,IAAI,CAAA;AACb,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,cAAc,CAAC,GAAyB,EAAE,EAAU,EAAE,MAA+B;IACnG,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC/B,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAA;IACpC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1C,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,MAA8C;IAE9C,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IACxC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAA;IAE9B,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAA;IAC3B,MAAM,MAAM,GAAG,GAAG,IAAI,MAAM,CAAA;IAC5B,MAAM,GAAG,GAAG,GAAG,IAAI,QAAQ,UAAU,EAAE,EAAE,CAAA;IACzC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC5B,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;QAClC,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAA;QAC7D,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,wCAAwC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,eAAe,EAAE,CAAC,CAAA;QACxG,CAAC;QACD,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACvB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QACjC,MAAM,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC5C,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}