@lolkda/dsh-prompt-manager 3.0.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/LICENSE +21 -0
- package/README.md +606 -0
- package/client/client.js +2320 -0
- package/cordis.patch.yml +20 -0
- package/environment.md +24 -0
- package/lib/entries.js +303 -0
- package/lib/entries.js.map +1 -0
- package/lib/guard.js +134 -0
- package/lib/guard.js.map +1 -0
- package/lib/index.js +959 -0
- package/lib/index.js.map +1 -0
- package/lib/net.js +179 -0
- package/lib/net.js.map +1 -0
- package/lib/pack.js +327 -0
- package/lib/pack.js.map +1 -0
- package/lib/probe.js +251 -0
- package/lib/probe.js.map +1 -0
- package/lib/routes.js +718 -0
- package/lib/routes.js.map +1 -0
- package/lib/scripts.js +803 -0
- package/lib/scripts.js.map +1 -0
- package/lib/source.js +308 -0
- package/lib/source.js.map +1 -0
- package/lib/store.js +223 -0
- package/lib/store.js.map +1 -0
- package/lib/subscriptions.js +269 -0
- package/lib/subscriptions.js.map +1 -0
- package/lib/sync.js +646 -0
- package/lib/sync.js.map +1 -0
- package/lib/types/entries.d.ts +194 -0
- package/lib/types/entries.d.ts.map +1 -0
- package/lib/types/guard.d.ts +63 -0
- package/lib/types/guard.d.ts.map +1 -0
- package/lib/types/index.d.ts +176 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/net.d.ts +81 -0
- package/lib/types/net.d.ts.map +1 -0
- package/lib/types/pack.d.ts +298 -0
- package/lib/types/pack.d.ts.map +1 -0
- package/lib/types/probe.d.ts +150 -0
- package/lib/types/probe.d.ts.map +1 -0
- package/lib/types/routes.d.ts +85 -0
- package/lib/types/routes.d.ts.map +1 -0
- package/lib/types/scripts.d.ts +455 -0
- package/lib/types/scripts.d.ts.map +1 -0
- package/lib/types/source.d.ts +194 -0
- package/lib/types/source.d.ts.map +1 -0
- package/lib/types/store.d.ts +140 -0
- package/lib/types/store.d.ts.map +1 -0
- package/lib/types/subscriptions.d.ts +204 -0
- package/lib/types/subscriptions.d.ts.map +1 -0
- package/lib/types/sync.d.ts +248 -0
- package/lib/types/sync.d.ts.map +1 -0
- package/package.json +100 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# The dsh-prompt-manager bundle patch: mounting this package is one insert.
|
|
2
|
+
#
|
|
3
|
+
# A profile that installs this package gains this row automatically — `dsh plugin
|
|
4
|
+
# add` (and any other install path) reconciles `dsh.profile.bundles` against the
|
|
5
|
+
# installed dependencies, and a dependency whose manifest declares
|
|
6
|
+
# `dsh.bundle.patch` joins the layer stack. The row mounts the Host half, which is
|
|
7
|
+
# also what makes the browser half load: the client module system serves the
|
|
8
|
+
# `exports["./client"]` bundle of every package that declares `dsh.client` *and* is
|
|
9
|
+
# an active Loader entry.
|
|
10
|
+
#
|
|
11
|
+
# No `config` here on purpose: the plugin's own defaults (machine-environment facts
|
|
12
|
+
# registered as variables) are what a fresh install wants. Disable or repoint them
|
|
13
|
+
# in the profile's own cordis.patch.yml, which applies after every bundle layer.
|
|
14
|
+
#
|
|
15
|
+
# The entry id is plugin-owned and must not collide with another registry entry's
|
|
16
|
+
# entry IDs, so it is the package's own name rather than the bare `prompt-manager`.
|
|
17
|
+
|
|
18
|
+
- insert:
|
|
19
|
+
- id: dsh-prompt-manager
|
|
20
|
+
name: '@lolkda/dsh-prompt-manager'
|
package/environment.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Machine environment
|
|
2
|
+
|
|
3
|
+
Detected on the machine running the DSH host process, and refreshed whenever the prompt plugin mounts. Every value below is measured rather than assumed — when one of them conflicts with what you observe, trust the observation.
|
|
4
|
+
|
|
5
|
+
## System
|
|
6
|
+
|
|
7
|
+
- {{os}}, release `{{os_release}}` (`{{platform}}` / `{{arch}}`)
|
|
8
|
+
|
|
9
|
+
## Shells
|
|
10
|
+
|
|
11
|
+
- **bash** `{{bash}}` — write POSIX syntax: `&&`, `$VAR`, forward slashes.
|
|
12
|
+
- **PowerShell** `pwsh` `{{pwsh}}`
|
|
13
|
+
- Use PowerShell 7 or newer. Windows PowerShell 5.1 is not UTF-8 by default — file writes go through the system ANSI code page, and what it pipes to native programs differs as well — so non-ASCII text is mangled or fails outright. Do not fall back to it.
|
|
14
|
+
- A value of `(not installed)` above means this machine has no usable PowerShell; that is not a reason to reach for 5.1.
|
|
15
|
+
|
|
16
|
+
## Version control
|
|
17
|
+
|
|
18
|
+
- **git** `{{git}}`
|
|
19
|
+
- A repository with no committer identity fails its first commit with `unable to auto-detect email`. Check before committing (`git config user.email`), and where the repository already has commits, reuse their author rather than inventing one.
|
|
20
|
+
|
|
21
|
+
## Languages
|
|
22
|
+
|
|
23
|
+
- **Node** `{{node}}`
|
|
24
|
+
- **Python** `{{python}}` — the command is normally `python`. On Windows `python3` may be an App Execution Alias stub that starts, prints nothing, and reports no error, so a silent `python3 --version` is not evidence that Python is missing.
|
package/lib/entries.js
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The prompt index: entry identity and the settings schema that carries one
|
|
3
|
+
* section per entry.
|
|
4
|
+
*
|
|
5
|
+
* An entry's markdown body lives in one file per entry under the store
|
|
6
|
+
* directory; everything else about it — title, order, whether it is injected —
|
|
7
|
+
* lives in the `prompt-manager` settings namespace this module describes. Keeping
|
|
8
|
+
* the index in the settings document means the browser gets reads, writes,
|
|
9
|
+
* revision fencing, and the "user overrode this" flag from the shared settings
|
|
10
|
+
* transport, while the bodies stay plain `.md` files a person can edit directly.
|
|
11
|
+
* The same namespace carries the presets: named selections that decide injection
|
|
12
|
+
* on their own while one of them is active, so a single `activePreset` write
|
|
13
|
+
* swaps the whole set without touching any entry.
|
|
14
|
+
*
|
|
15
|
+
* Entry bodies live either as plain `.md` files a person can edit directly, or
|
|
16
|
+
* as one markdown file shipped with this package: a fresh install starts with
|
|
17
|
+
* the built-in machine-environment prompt, and anything a person writes or
|
|
18
|
+
* subscribes overrides it.
|
|
19
|
+
*
|
|
20
|
+
* @module @lolkda/dsh-prompt-manager/entries
|
|
21
|
+
*/
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
/** Order handed to the first entry a person adds; later additions sort after it. */
|
|
25
|
+
export const USER_ORDER_START = 30;
|
|
26
|
+
/** At most this many entries may be active at once. */
|
|
27
|
+
export const MAX_ENTRIES = 50;
|
|
28
|
+
/** At most this many presets may be configured. */
|
|
29
|
+
export const MAX_PRESETS = 20;
|
|
30
|
+
/** At most this many entries one preset may select. */
|
|
31
|
+
export const MAX_PRESET_ENTRIES = MAX_ENTRIES;
|
|
32
|
+
/** Ref a source starts on when the settings page names none. */
|
|
33
|
+
export const DEFAULT_SOURCE_REF = 'main';
|
|
34
|
+
/** Largest accepted body, in bytes. */
|
|
35
|
+
export const MAX_BODY_BYTES = 256 * 1024;
|
|
36
|
+
/** Largest accepted title, in characters. */
|
|
37
|
+
export const MAX_TITLE_LENGTH = 120;
|
|
38
|
+
/** Largest accepted id, in characters. */
|
|
39
|
+
export const MAX_ID_LENGTH = 64;
|
|
40
|
+
/**
|
|
41
|
+
* Entry id grammar. The id becomes a file name and a prompt-section name
|
|
42
|
+
* suffix, so it stays lowercase, hyphenated, and path-safe by construction.
|
|
43
|
+
*/
|
|
44
|
+
export const ENTRY_ID_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
45
|
+
/** The prompts this package ships. */
|
|
46
|
+
export const BUILTIN_PROMPTS = [
|
|
47
|
+
{
|
|
48
|
+
id: 'env',
|
|
49
|
+
title: '机器环境',
|
|
50
|
+
order: 5,
|
|
51
|
+
file: new URL('../environment.md', import.meta.url),
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
/**
|
|
55
|
+
* The base layer's entries: one per {@link BUILTIN_PROMPTS} entry, enabled.
|
|
56
|
+
*
|
|
57
|
+
* They behave like any other entry — the page lists them, a write overrides
|
|
58
|
+
* them, a toggle disables them — so the built-in prose is a starting point
|
|
59
|
+
* rather than something the deployment cannot reach.
|
|
60
|
+
*
|
|
61
|
+
* @returns fresh entry records, safe to hand to a settings base layer.
|
|
62
|
+
*/
|
|
63
|
+
export function builtinEntries() {
|
|
64
|
+
return BUILTIN_PROMPTS.map((prompt) => ({
|
|
65
|
+
id: prompt.id,
|
|
66
|
+
title: prompt.title,
|
|
67
|
+
order: prompt.order,
|
|
68
|
+
enabled: true,
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The packaged body for one entry id.
|
|
73
|
+
* @param id - entry id to look up.
|
|
74
|
+
* @returns the exact UTF-8 markdown, or `undefined` when the package ships none
|
|
75
|
+
* for that id, or the packaged file cannot be read.
|
|
76
|
+
*/
|
|
77
|
+
export function readBuiltinBody(id) {
|
|
78
|
+
const prompt = BUILTIN_PROMPTS.find((candidate) => candidate.id === id);
|
|
79
|
+
if (prompt === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
try {
|
|
82
|
+
const text = readFileSync(fileURLToPath(prompt.file), 'utf8');
|
|
83
|
+
return text.trim().length === 0 ? undefined : text;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Whether a value is a usable entry id. */
|
|
90
|
+
export function isEntryId(value) {
|
|
91
|
+
return typeof value === 'string' && value.length <= MAX_ID_LENGTH && ENTRY_ID_PATTERN.test(value);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Turn a human title into an unused entry id.
|
|
95
|
+
*
|
|
96
|
+
* Only ASCII letters and digits survive, so a title written entirely in a
|
|
97
|
+
* non-Latin script falls back to the `entry` stem. That is deliberate: the id
|
|
98
|
+
* is an internal handle (file name and section-name suffix), never user copy.
|
|
99
|
+
*
|
|
100
|
+
* @param title - the label a person typed.
|
|
101
|
+
* @param taken - ids already in use.
|
|
102
|
+
* @returns a lowercase, hyphenated, unused id.
|
|
103
|
+
*/
|
|
104
|
+
export function entryIdFor(title, taken) {
|
|
105
|
+
const stem = title
|
|
106
|
+
.toLowerCase()
|
|
107
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
108
|
+
.replace(/^-+|-+$/g, '')
|
|
109
|
+
.slice(0, 32);
|
|
110
|
+
const base = stem.length >= 2 ? stem : 'entry';
|
|
111
|
+
const used = new Set(taken);
|
|
112
|
+
if (!used.has(base))
|
|
113
|
+
return base;
|
|
114
|
+
for (let suffix = 2; suffix < 1000; suffix += 1) {
|
|
115
|
+
const candidate = `${base.slice(0, 28)}-${String(suffix)}`;
|
|
116
|
+
if (!used.has(candidate))
|
|
117
|
+
return candidate;
|
|
118
|
+
}
|
|
119
|
+
return `${base.slice(0, 24)}-${String(Date.now())}`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Keep one id when it is free, or take the nearest free variant of it.
|
|
123
|
+
*
|
|
124
|
+
* For the places where the id *is* the identity rather than a handle derived
|
|
125
|
+
* from a title: a subscribed entry's body is looked up by id upstream, so an
|
|
126
|
+
* imported `env` that collides is far better off as `env-2` than as whatever a
|
|
127
|
+
* title — possibly written entirely in a non-Latin script — would slug to.
|
|
128
|
+
*
|
|
129
|
+
* @param preferred - the id that was asked for.
|
|
130
|
+
* @param taken - ids already in use.
|
|
131
|
+
* @returns `preferred`, or a `-2`-suffixed variant of its stem.
|
|
132
|
+
*/
|
|
133
|
+
export function freeId(preferred, taken) {
|
|
134
|
+
const used = new Set(taken);
|
|
135
|
+
if (isEntryId(preferred) && !used.has(preferred))
|
|
136
|
+
return preferred;
|
|
137
|
+
const stem = (isEntryId(preferred) ? preferred : 'entry').replace(/-\d+$/, '').slice(0, 28);
|
|
138
|
+
const base = stem.length >= 2 ? stem : 'entry';
|
|
139
|
+
if (!used.has(base))
|
|
140
|
+
return base;
|
|
141
|
+
for (let suffix = 2; suffix < 1000; suffix += 1) {
|
|
142
|
+
const candidate = `${base.slice(0, 28)}-${String(suffix)}`;
|
|
143
|
+
if (!used.has(candidate))
|
|
144
|
+
return candidate;
|
|
145
|
+
}
|
|
146
|
+
return `${base.slice(0, 24)}-${String(Date.now())}`;
|
|
147
|
+
}
|
|
148
|
+
/** One usable entry, or `undefined` when the raw value is unusable. */
|
|
149
|
+
function toEntry(raw) {
|
|
150
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
151
|
+
return undefined;
|
|
152
|
+
const record = raw;
|
|
153
|
+
const { id, title, order, enabled, source } = record;
|
|
154
|
+
if (!isEntryId(id))
|
|
155
|
+
return undefined;
|
|
156
|
+
if (typeof order !== 'number' || !Number.isFinite(order))
|
|
157
|
+
return undefined;
|
|
158
|
+
if (typeof enabled !== 'boolean')
|
|
159
|
+
return undefined;
|
|
160
|
+
const label = typeof title === 'string' ? title.trim() : '';
|
|
161
|
+
const entry = {
|
|
162
|
+
id,
|
|
163
|
+
title: label.length === 0 ? id : label.slice(0, MAX_TITLE_LENGTH),
|
|
164
|
+
order,
|
|
165
|
+
enabled,
|
|
166
|
+
};
|
|
167
|
+
if (typeof source === 'string' && source.length > 0)
|
|
168
|
+
entry.source = source.slice(0, 64);
|
|
169
|
+
return entry;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Narrow one resolved settings value into an index. A hand-edited document can
|
|
173
|
+
* hold anything, so unusable entries are dropped rather than thrown: the worst
|
|
174
|
+
* case is a prompt with fewer sections, never a session that cannot assemble.
|
|
175
|
+
*
|
|
176
|
+
* @param raw - the resolved `prompt-manager` namespace value.
|
|
177
|
+
* @returns the usable entries, deduplicated by id and capped at {@link MAX_ENTRIES}.
|
|
178
|
+
*/
|
|
179
|
+
export function parseEntries(raw) {
|
|
180
|
+
const list = typeof raw === 'object' && raw !== null && !Array.isArray(raw)
|
|
181
|
+
? raw['entries']
|
|
182
|
+
: undefined;
|
|
183
|
+
if (!Array.isArray(list))
|
|
184
|
+
return [];
|
|
185
|
+
const entries = [];
|
|
186
|
+
const seen = new Set();
|
|
187
|
+
for (const candidate of list) {
|
|
188
|
+
const entry = toEntry(candidate);
|
|
189
|
+
if (entry === undefined || seen.has(entry.id))
|
|
190
|
+
continue;
|
|
191
|
+
seen.add(entry.id);
|
|
192
|
+
entries.push(entry);
|
|
193
|
+
if (entries.length >= MAX_ENTRIES)
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
return entries;
|
|
197
|
+
}
|
|
198
|
+
/** One usable preset, or `undefined` when the raw value is unusable. */
|
|
199
|
+
function toPreset(raw) {
|
|
200
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
201
|
+
return undefined;
|
|
202
|
+
const record = raw;
|
|
203
|
+
const { id, name, entries } = record;
|
|
204
|
+
if (!isEntryId(id))
|
|
205
|
+
return undefined;
|
|
206
|
+
const label = typeof name === 'string' ? name.trim() : '';
|
|
207
|
+
const chosen = [];
|
|
208
|
+
const seen = new Set();
|
|
209
|
+
if (Array.isArray(entries)) {
|
|
210
|
+
for (const candidate of entries) {
|
|
211
|
+
// An id the index does not carry right now is kept: it may belong to a
|
|
212
|
+
// subscription that has not come back yet, and dropping it here would
|
|
213
|
+
// silently rewrite what the person selected.
|
|
214
|
+
if (typeof candidate !== 'string' || !isEntryId(candidate) || seen.has(candidate))
|
|
215
|
+
continue;
|
|
216
|
+
seen.add(candidate);
|
|
217
|
+
chosen.push(candidate);
|
|
218
|
+
if (chosen.length >= MAX_PRESET_ENTRIES)
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return { id, name: label.length === 0 ? id : label.slice(0, MAX_TITLE_LENGTH), entries: chosen };
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Narrow a resolved settings value into the preset list. Like {@link parseEntries},
|
|
226
|
+
* a hand-edited document can hold anything, so unusable presets are dropped
|
|
227
|
+
* rather than thrown: the worst case is a smaller list, never an assembly that
|
|
228
|
+
* cannot be built.
|
|
229
|
+
*
|
|
230
|
+
* @param raw - the resolved `presets` field.
|
|
231
|
+
* @returns the usable presets, deduplicated by id and capped at {@link MAX_PRESETS}.
|
|
232
|
+
*/
|
|
233
|
+
export function parsePresets(raw) {
|
|
234
|
+
if (!Array.isArray(raw))
|
|
235
|
+
return [];
|
|
236
|
+
const presets = [];
|
|
237
|
+
const seen = new Set();
|
|
238
|
+
for (const candidate of raw) {
|
|
239
|
+
const preset = toPreset(candidate);
|
|
240
|
+
if (preset === undefined || seen.has(preset.id))
|
|
241
|
+
continue;
|
|
242
|
+
seen.add(preset.id);
|
|
243
|
+
presets.push(preset);
|
|
244
|
+
if (presets.length >= MAX_PRESETS)
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
return presets;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* The id of the preset in force.
|
|
251
|
+
* @param raw - the resolved `activePreset` field.
|
|
252
|
+
* @returns the configured id, or `''` when the deployment runs without a preset.
|
|
253
|
+
*/
|
|
254
|
+
export function activePresetOf(raw) {
|
|
255
|
+
return typeof raw === 'string' ? raw.trim() : '';
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Build the `prompt-manager` namespace schema.
|
|
259
|
+
*
|
|
260
|
+
* @param factory - the schemastery factory loaded at mount.
|
|
261
|
+
* @returns a schema carrying the entry index, the subscriptions, and the
|
|
262
|
+
* outbound settings the engine reads.
|
|
263
|
+
*/
|
|
264
|
+
export function buildIndexSchema(factory) {
|
|
265
|
+
const entry = factory.object({
|
|
266
|
+
id: factory.string().required(),
|
|
267
|
+
title: factory.string().default(''),
|
|
268
|
+
order: factory.number().default(USER_ORDER_START),
|
|
269
|
+
enabled: factory.boolean().default(true),
|
|
270
|
+
// No default: a local entry must resolve without the field at all. With
|
|
271
|
+
// `.default('')` every entry carried `source: ''`, which reads as
|
|
272
|
+
// "subscribed" to anything testing presence rather than value, and a
|
|
273
|
+
// settings write-back would then persist the phantom field to disk.
|
|
274
|
+
source: factory.string(),
|
|
275
|
+
});
|
|
276
|
+
const source = factory.object({
|
|
277
|
+
id: factory.string().required(),
|
|
278
|
+
repo: factory.string().required(),
|
|
279
|
+
ref: factory.string().default(DEFAULT_SOURCE_REF),
|
|
280
|
+
mirror: factory.string().default(''),
|
|
281
|
+
enabled: factory.boolean().default(true),
|
|
282
|
+
});
|
|
283
|
+
const preset = factory.object({
|
|
284
|
+
id: factory.string().required(),
|
|
285
|
+
name: factory.string().default(''),
|
|
286
|
+
entries: factory.array(factory.string()).default([]),
|
|
287
|
+
});
|
|
288
|
+
const proxy = factory.object({
|
|
289
|
+
kind: factory.string().default('none'),
|
|
290
|
+
url: factory.string().default(''),
|
|
291
|
+
}).default({ kind: 'none', url: '' });
|
|
292
|
+
return factory.object({
|
|
293
|
+
entries: factory.array(entry).default([]),
|
|
294
|
+
presets: factory.array(preset).default([]),
|
|
295
|
+
// No default beyond the empty string: an unset preset means the entries'
|
|
296
|
+
// own switches decide, which is what a deployment that never made one gets.
|
|
297
|
+
activePreset: factory.string().default(''),
|
|
298
|
+
sources: factory.array(source).default([]),
|
|
299
|
+
mirror: factory.string().default(''),
|
|
300
|
+
proxy,
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=entries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entries.js","sourceRoot":"","sources":["../src/entries.ts"],"names":[],"mappings":"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"}
|
package/lib/guard.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The reference guard: keeps a prompt body from breaking the whole assembly.
|
|
3
|
+
*
|
|
4
|
+
* The registry interpolates section text strictly — a reference it cannot
|
|
5
|
+
* resolve, and a reference whose shape is not a variable name, both throw, and
|
|
6
|
+
* one throwing section fails the entire assembly. Since the plugin serves text
|
|
7
|
+
* that a person can also hand-edit in `sections/`, one stray `{{ }}` in a
|
|
8
|
+
* markdown file would otherwise break every model step of the profile.
|
|
9
|
+
*
|
|
10
|
+
* This module therefore mirrors the registry's own scan, reference for
|
|
11
|
+
* reference, and defuses exactly the groups the registry would throw on: it
|
|
12
|
+
* puts a zero-width space after each of the two opening braces, so the text
|
|
13
|
+
* reads the same to a model but no longer starts a reference. Everything the
|
|
14
|
+
* registry can resolve is left untouched, so a variable another row registers
|
|
15
|
+
* still interpolates normally.
|
|
16
|
+
*
|
|
17
|
+
* The scan below is a deliberate mirror of the registry's `interpolate`
|
|
18
|
+
* (`@deepseek-ai/dsh-system-prompt`, `lib/index.js`, its `GROUP_AT` and
|
|
19
|
+
* `VARIABLE_NAME` constants). When that implementation changes shape, this one
|
|
20
|
+
* has to follow.
|
|
21
|
+
*
|
|
22
|
+
* @module @lolkda/dsh-prompt-manager/guard
|
|
23
|
+
*/
|
|
24
|
+
/** A complete `{{...}}` group at the scan position, as the registry reads it. */
|
|
25
|
+
const GROUP_AT = /^\{\{([^{}]*)\}\}/;
|
|
26
|
+
/** Variable-name grammar the registry enforces between the braces. */
|
|
27
|
+
const VARIABLE_NAME = /^[a-z][a-z0-9_]*$/;
|
|
28
|
+
/** Longest snippet of an unusable reference carried into a report. */
|
|
29
|
+
const SNIPPET_LENGTH = 16;
|
|
30
|
+
/**
|
|
31
|
+
* Zero-width space, inserted after each brace of a reference that must not
|
|
32
|
+
* resolve. It is invisible in rendered prose, and because every emitted `{` is
|
|
33
|
+
* followed by one, neither the escaped reference nor its neighbours can ever
|
|
34
|
+
* re-form a `{{` pair.
|
|
35
|
+
*/
|
|
36
|
+
export const ESCAPE_MARK = '\u200b';
|
|
37
|
+
/** One defused reference, as it appears in the guarded text. */
|
|
38
|
+
function escapedOpener() {
|
|
39
|
+
return `{${ESCAPE_MARK}{${ESCAPE_MARK}`;
|
|
40
|
+
}
|
|
41
|
+
/** Whether one reference name resolves for the assembly being rendered. */
|
|
42
|
+
function resolvable(name, variables) {
|
|
43
|
+
return VARIABLE_NAME.test(name) && Object.hasOwn(variables, name) && variables[name] !== undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Defuse every reference the registry would throw on.
|
|
47
|
+
*
|
|
48
|
+
* A reference is defused when its shape is not a variable name, when no
|
|
49
|
+
* variable of that name exists for this assembly, or when the variable exists
|
|
50
|
+
* but has no value. A lone `{{` with no later `}}` is literal prose to the
|
|
51
|
+
* registry and is left exactly as it is.
|
|
52
|
+
*
|
|
53
|
+
* @param text - the section text about to be handed to the registry.
|
|
54
|
+
* @param variables - the names the registry will resolve for this assembly.
|
|
55
|
+
* @returns the safe text and the references that were defused.
|
|
56
|
+
*/
|
|
57
|
+
export function sanitizeReferences(text, variables) {
|
|
58
|
+
const escaped = [];
|
|
59
|
+
let result = '';
|
|
60
|
+
let last = 0;
|
|
61
|
+
let open = text.indexOf('{{');
|
|
62
|
+
while (open >= 0) {
|
|
63
|
+
const group = GROUP_AT.exec(text.slice(open));
|
|
64
|
+
if (group === null) {
|
|
65
|
+
// No complete group here. The registry only fails a stray opener when a
|
|
66
|
+
// closer follows it somewhere; otherwise the opener is ordinary prose.
|
|
67
|
+
if (text.indexOf('}}', open + 2) >= 0) {
|
|
68
|
+
result += text.slice(last, open) + escapedOpener();
|
|
69
|
+
escaped.push(text.slice(open, open + SNIPPET_LENGTH));
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
result += text.slice(last, open + 2);
|
|
73
|
+
}
|
|
74
|
+
last = open + 2;
|
|
75
|
+
open = text.indexOf('{{', last);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const name = group[0].slice(2, -2);
|
|
79
|
+
if (resolvable(name, variables)) {
|
|
80
|
+
result += text.slice(last, open + group[0].length);
|
|
81
|
+
last = open + group[0].length;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// Defuse the opener and keep the body of the reference verbatim: the
|
|
85
|
+
// prose a person wrote must survive, closing braces included.
|
|
86
|
+
result += text.slice(last, open) + escapedOpener();
|
|
87
|
+
escaped.push(group[0]);
|
|
88
|
+
last = open + 2;
|
|
89
|
+
}
|
|
90
|
+
open = text.indexOf('{{', last);
|
|
91
|
+
}
|
|
92
|
+
return { text: result + text.slice(last), escaped };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The references that can never resolve, whatever else is registered.
|
|
96
|
+
*
|
|
97
|
+
* A malformed group throws for every deployment, so a save can refuse it up
|
|
98
|
+
* front. A well-formed name is not listed: another row may register it, and a
|
|
99
|
+
* name that is merely unregistered today is a body the person may still be
|
|
100
|
+
* writing.
|
|
101
|
+
*
|
|
102
|
+
* @param text - the body about to be stored.
|
|
103
|
+
* @returns the unusable references, deduplicated, in the order they appear.
|
|
104
|
+
*/
|
|
105
|
+
export function malformedReferences(text) {
|
|
106
|
+
const found = [];
|
|
107
|
+
const seen = new Set();
|
|
108
|
+
let last = 0;
|
|
109
|
+
let open = text.indexOf('{{');
|
|
110
|
+
while (open >= 0) {
|
|
111
|
+
const group = GROUP_AT.exec(text.slice(open));
|
|
112
|
+
if (group === null) {
|
|
113
|
+
if (text.indexOf('}}', open + 2) >= 0) {
|
|
114
|
+
const snippet = text.slice(open, open + SNIPPET_LENGTH);
|
|
115
|
+
if (!seen.has(snippet)) {
|
|
116
|
+
seen.add(snippet);
|
|
117
|
+
found.push(snippet);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
last = open + 2;
|
|
121
|
+
open = text.indexOf('{{', last);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const name = group[0].slice(2, -2);
|
|
125
|
+
if (!VARIABLE_NAME.test(name) && !seen.has(group[0])) {
|
|
126
|
+
seen.add(group[0]);
|
|
127
|
+
found.push(group[0]);
|
|
128
|
+
}
|
|
129
|
+
last = open + group[0].length;
|
|
130
|
+
open = text.indexOf('{{', last);
|
|
131
|
+
}
|
|
132
|
+
return found;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=guard.js.map
|
package/lib/guard.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.js","sourceRoot":"","sources":["../src/guard.ts"],"names":[],"mappings":"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"}
|