@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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +606 -0
  3. package/client/client.js +2320 -0
  4. package/cordis.patch.yml +20 -0
  5. package/environment.md +24 -0
  6. package/lib/entries.js +303 -0
  7. package/lib/entries.js.map +1 -0
  8. package/lib/guard.js +134 -0
  9. package/lib/guard.js.map +1 -0
  10. package/lib/index.js +959 -0
  11. package/lib/index.js.map +1 -0
  12. package/lib/net.js +179 -0
  13. package/lib/net.js.map +1 -0
  14. package/lib/pack.js +327 -0
  15. package/lib/pack.js.map +1 -0
  16. package/lib/probe.js +251 -0
  17. package/lib/probe.js.map +1 -0
  18. package/lib/routes.js +718 -0
  19. package/lib/routes.js.map +1 -0
  20. package/lib/scripts.js +803 -0
  21. package/lib/scripts.js.map +1 -0
  22. package/lib/source.js +308 -0
  23. package/lib/source.js.map +1 -0
  24. package/lib/store.js +223 -0
  25. package/lib/store.js.map +1 -0
  26. package/lib/subscriptions.js +269 -0
  27. package/lib/subscriptions.js.map +1 -0
  28. package/lib/sync.js +646 -0
  29. package/lib/sync.js.map +1 -0
  30. package/lib/types/entries.d.ts +194 -0
  31. package/lib/types/entries.d.ts.map +1 -0
  32. package/lib/types/guard.d.ts +63 -0
  33. package/lib/types/guard.d.ts.map +1 -0
  34. package/lib/types/index.d.ts +176 -0
  35. package/lib/types/index.d.ts.map +1 -0
  36. package/lib/types/net.d.ts +81 -0
  37. package/lib/types/net.d.ts.map +1 -0
  38. package/lib/types/pack.d.ts +298 -0
  39. package/lib/types/pack.d.ts.map +1 -0
  40. package/lib/types/probe.d.ts +150 -0
  41. package/lib/types/probe.d.ts.map +1 -0
  42. package/lib/types/routes.d.ts +85 -0
  43. package/lib/types/routes.d.ts.map +1 -0
  44. package/lib/types/scripts.d.ts +455 -0
  45. package/lib/types/scripts.d.ts.map +1 -0
  46. package/lib/types/source.d.ts +194 -0
  47. package/lib/types/source.d.ts.map +1 -0
  48. package/lib/types/store.d.ts +140 -0
  49. package/lib/types/store.d.ts.map +1 -0
  50. package/lib/types/subscriptions.d.ts +204 -0
  51. package/lib/types/subscriptions.d.ts.map +1 -0
  52. package/lib/types/sync.d.ts +248 -0
  53. package/lib/types/sync.d.ts.map +1 -0
  54. package/package.json +100 -0
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Preset packs: one preset, the bodies of its local members, and enough
3
+ * provenance to say where the bodies that are *not* in the pack come from.
4
+ *
5
+ * A pack is plain JSON a person can read, diff, mail, and keep. It carries no
6
+ * code: scripts stay on the machine that wrote them, and a pack cannot ask for
7
+ * one. Everything in this module is pure — building, validating, and planning an
8
+ * import are all functions of their arguments — so the rules a pack has to pass
9
+ * are testable without an HTTP request, a store, or a settings namespace.
10
+ *
11
+ * The split of responsibility is deliberate:
12
+ *
13
+ * - {@link buildPack} turns already-resolved members into a pack. Reading bodies
14
+ * and subscription origins is the host's job, because only it knows them.
15
+ * - {@link parsePack} decides whether a foreign file is a pack this build can
16
+ * use at all, and refuses by naming the entry that is wrong.
17
+ * - {@link planImport} works out which ids the entries will take on this machine
18
+ * and rewrites the preset's membership to match, without touching anything.
19
+ *
20
+ * @module @lolkda/dsh-prompt-manager/pack
21
+ */
22
+ import { type PromptPreset } from './entries.js';
23
+ /** Marker every pack carries, so a foreign JSON file is refused by name. */
24
+ export declare const PACK_FORMAT = "dsh-prompt-manager-pack";
25
+ /** Pack schema this build writes, and the only one it reads. */
26
+ export declare const PACK_VERSION = 1;
27
+ /**
28
+ * Largest pack accepted on import, in bytes.
29
+ *
30
+ * A pack can carry up to {@link MAX_ENTRIES} bodies of {@link MAX_BODY_BYTES}
31
+ * each, so the route's ordinary JSON limit — sized for one body — is far too
32
+ * small here. This is the ceiling that replaces it, and it is also the largest
33
+ * body the route will read at all.
34
+ */
35
+ export declare const MAX_PACK_BYTES: number;
36
+ /** At most this many entries one pack may declare. Mirrors the index's own cap. */
37
+ export declare const MAX_PACK_ENTRIES = 50;
38
+ /** Where a subscribed entry's body comes from, as recorded in a pack. */
39
+ export interface PackSourceRef {
40
+ /** Source slug the entry is subscribed to, e.g. `lolkda-dsh-prompt-pack`. */
41
+ slug: string;
42
+ /** `owner/repo`, when the exporting machine still had that source configured. */
43
+ repo?: string | undefined;
44
+ /** The ref in force there, e.g. `main`. */
45
+ ref?: string | undefined;
46
+ /** Path inside the source's workspace, e.g. `ctf.md`. */
47
+ file?: string | undefined;
48
+ }
49
+ /** Where an exported body came from. */
50
+ export type PackOrigin = 'local' | 'builtin';
51
+ /** One entry inside a pack. */
52
+ export interface PackEntry {
53
+ /** Id it had on the exporting machine; not necessarily free on this one. */
54
+ id: string;
55
+ /** Human label, used to allocate a new id when this one is taken. */
56
+ title: string;
57
+ /** Section placement, carried over as written. */
58
+ order: number;
59
+ /** The entry's own switch, carried over as written. */
60
+ enabled: boolean;
61
+ /** Body text. Absent for a subscribed entry, whose body belongs to a source. */
62
+ body?: string | undefined;
63
+ /** Which layer supplied {@link PackEntry.body}. Absent for a subscription. */
64
+ origin?: PackOrigin | undefined;
65
+ /** Present instead of a body when the entry is a subscription. */
66
+ source?: PackSourceRef | undefined;
67
+ }
68
+ /** The preset a pack carries. */
69
+ export interface PackPreset {
70
+ /** Id it had on the exporting machine; not necessarily free on this one. */
71
+ id: string;
72
+ /** Display name; kept verbatim on import even when the id has to change. */
73
+ name: string;
74
+ /** Member ids, referring to {@link PromptPack.entries}. */
75
+ entries: string[];
76
+ }
77
+ /** A pack this build understands. */
78
+ export interface PromptPack {
79
+ /** Always {@link PACK_FORMAT}. */
80
+ format: string;
81
+ /** Always {@link PACK_VERSION}. */
82
+ version: number;
83
+ /** When the exporting machine wrote it, for a human reading the file. */
84
+ exportedAt: string;
85
+ /** What wrote it, for a human reading the file. */
86
+ generator: {
87
+ plugin: string;
88
+ pluginVersion: string;
89
+ };
90
+ /** The preset being moved. */
91
+ preset: PackPreset;
92
+ /** Its members, in the order the exporting index held them. */
93
+ entries: PackEntry[];
94
+ /** Members the preset named that no longer existed when the pack was written. */
95
+ missing: string[];
96
+ }
97
+ /** Why a pack was refused. */
98
+ export interface PackRefusal {
99
+ ok: false;
100
+ /** Stable code the browser can branch on. */
101
+ code: PackRefusalCode;
102
+ /** Message written for the person reading the page. */
103
+ message: string;
104
+ }
105
+ /** The refusal codes a pack can be turned down with. */
106
+ export type PackRefusalCode = 'bad-format' | 'bad-version' | 'bad-preset' | 'bad-entry' | 'bad-reference' | 'too-large' | 'too-many-entries';
107
+ /** One member of a preset, resolved for export. */
108
+ export interface PackMember {
109
+ /** Entry id. */
110
+ id: string;
111
+ /** Human label. */
112
+ title: string;
113
+ /** Section placement. */
114
+ order: number;
115
+ /** The entry's own switch. */
116
+ enabled: boolean;
117
+ /** Resolved body, when this machine has one. */
118
+ body?: string | undefined;
119
+ /** Which layer supplied the body. */
120
+ origin?: PackOrigin | undefined;
121
+ /** Subscription origin, when the body belongs to a source. */
122
+ source?: PackSourceRef | undefined;
123
+ }
124
+ /** Everything {@link buildPack} needs, all of it already resolved. */
125
+ export interface PackExportInput {
126
+ /** The preset being exported. */
127
+ preset: PromptPreset;
128
+ /** Its resolvable members, in the order the pack should carry them. */
129
+ members: PackMember[];
130
+ /** Member ids the preset names that this machine cannot resolve. */
131
+ missing?: string[] | undefined;
132
+ /** This plugin's package name, recorded in the pack's header. */
133
+ pluginName: string;
134
+ /** This plugin's version, recorded in the pack's header. */
135
+ pluginVersion: string;
136
+ /** Clock, for tests; defaults to now. */
137
+ now?: Date | undefined;
138
+ }
139
+ /** One entry an import would create. */
140
+ export interface PackImportEntry {
141
+ /** The id it will take on this machine. */
142
+ id: string;
143
+ /** Human label. */
144
+ title: string;
145
+ /** Section placement. */
146
+ order: number;
147
+ /** Whether it contributes while no preset is in force. */
148
+ enabled: boolean;
149
+ /** Body to write, absent for an entry whose text a source supplies. */
150
+ body?: string | undefined;
151
+ /** Which layer the body came from. */
152
+ origin?: PackOrigin | undefined;
153
+ /** Source slug to record in the index, when the entry is a subscription. */
154
+ source?: string | undefined;
155
+ /** The id this entry had on the exporting machine, when it had to change. */
156
+ renamedFrom?: string | undefined;
157
+ }
158
+ /** What an import would do, ready to be checked and then carried out. */
159
+ export interface PackImportPlan {
160
+ /** Entries to create, in pack order. */
161
+ entries: PackImportEntry[];
162
+ /** The preset to create, with membership pointing at the ids above. */
163
+ preset: PromptPreset;
164
+ /** Every id that had to change, for the report. */
165
+ renamed: Array<{
166
+ from: string;
167
+ to: string;
168
+ }>;
169
+ /** Titles whose bodies this machine will not have until a source is set up. */
170
+ noBody: string[];
171
+ /**
172
+ * Titles that arrived as subscriptions but had to give up their id, and with
173
+ * it the ability to read their body from the source. They are imported as
174
+ * ordinary empty entries, and this is how the page says so.
175
+ */
176
+ sourceDropped: string[];
177
+ /** Preset members the pack itself could not carry (already gone at export). */
178
+ missingMembers: string[];
179
+ }
180
+ /** The result of planning an import. */
181
+ export type PackImportResult = {
182
+ ok: true;
183
+ plan: PackImportPlan;
184
+ } | PackRefusal;
185
+ /** What an import did, in the words the page reports it with. */
186
+ export interface PackImportReport {
187
+ /** Entries created, in pack order. */
188
+ entries: Array<{
189
+ id: string;
190
+ title: string;
191
+ renamedFrom?: string | undefined;
192
+ }>;
193
+ /** The preset created, with membership already pointing at the ids above. */
194
+ preset: PromptPreset;
195
+ /** Every id that changed, so the page can say which entry is which. */
196
+ renamed: Array<{
197
+ from: string;
198
+ to: string;
199
+ }>;
200
+ /** Titles whose body the pack does not carry, because a source supplies it. */
201
+ noBody: string[];
202
+ /** Titles that arrived as subscriptions but could not keep their id. */
203
+ sourceDropped: string[];
204
+ /** Preset members the pack itself could not carry. */
205
+ missingMembers: string[];
206
+ /**
207
+ * Variable names the imported bodies reference that *this* plugin does not
208
+ * supply. Not proof of a broken prompt: another row may register them, and the
209
+ * reference guard renders whatever is left as prose and says so in the log.
210
+ */
211
+ unregistered: string[];
212
+ }
213
+ /** The result of carrying out an import. */
214
+ export type PackApplyResult = {
215
+ ok: true;
216
+ report: PackImportReport;
217
+ } | PackRefusal;
218
+ /** The result of reading a pack. */
219
+ export type PackParseResult = {
220
+ ok: true;
221
+ pack: PromptPack;
222
+ } | PackRefusal;
223
+ /**
224
+ * Assemble a pack from members whose bodies the host has already resolved.
225
+ *
226
+ * Refuses nothing: a member with no body is exactly what a subscribed entry
227
+ * looks like, and its provenance is what makes the pack usable somewhere else.
228
+ *
229
+ * @param input - the preset, its resolved members, and the version recording it.
230
+ * @returns the pack, ready to be serialized.
231
+ */
232
+ export declare function buildPack(input: PackExportInput): PromptPack;
233
+ /** Where an import's body files go. */
234
+ export interface PackBodySink {
235
+ /**
236
+ * Create one body file.
237
+ *
238
+ * Must refuse to replace a file that already exists: an id the planner
239
+ * believes is free may have been taken by somebody else in the meantime, and
240
+ * silently overwriting their body is the one outcome worse than failing.
241
+ */
242
+ write(id: string, body: string): void;
243
+ /**
244
+ * Remove one body file this call created.
245
+ *
246
+ * Expected to swallow its own failures — there is nothing useful to do about
247
+ * one at this point, and the original error is the one worth reporting.
248
+ */
249
+ remove(id: string): void;
250
+ }
251
+ /**
252
+ * Write the bodies an import carries, and take back whatever was written if one
253
+ * of them fails.
254
+ *
255
+ * An import that gets half-way leaves an index nobody has updated yet and a pile
256
+ * of files nothing points at, which is why the files go down first and the index
257
+ * last: a failure here removes exactly what this call created, so the machine
258
+ * ends up as it was, and importing the same pack again starts clean.
259
+ *
260
+ * @param entries - the planned entries, in pack order.
261
+ * @param sink - where the bodies go.
262
+ * @throws the sink's own error, after the rollback.
263
+ */
264
+ export declare function writePackBodies(entries: readonly PackImportEntry[], sink: PackBodySink): void;
265
+ /**
266
+ * Read a pack from an untrusted value.
267
+ *
268
+ * Strict about what cannot be recovered and forgiving about what can: a title is
269
+ * required because a missing id is derived from it, while an unusable id, a
270
+ * missing order, or an absent `enabled` are all things the importer decides
271
+ * again anyway. A body that no assembly could render is refused here rather than
272
+ * written into the index, because an index entry that cannot assemble fails
273
+ * every model step until somebody edits it.
274
+ *
275
+ * @param raw - the parsed JSON value.
276
+ * @returns the pack, or the first reason it is unusable.
277
+ */
278
+ export declare function parsePack(raw: unknown): PackParseResult;
279
+ /**
280
+ * Decide which ids an imported pack will take here, and what its preset will say.
281
+ *
282
+ * A taken id is not an error and not an overwrite: the entry gets a fresh id
283
+ * derived from its title, the preset's membership follows it, and the pack's
284
+ * display name is kept. Importing the same pack twice therefore produces two
285
+ * distinct sets rather than quietly rewriting the first one. Members the pack
286
+ * itself could not carry are kept in the preset as they were — the same rule the
287
+ * index uses for a subscription that may come back — and reported separately.
288
+ *
289
+ * @param pack - a pack that already passed {@link parsePack}.
290
+ * @param taken - ids already in use here: the index, the stored bodies, the
291
+ * built-ins, and the configured presets.
292
+ * @returns the plan, or why the pack does not fit on this machine.
293
+ */
294
+ export declare function planImport(pack: PromptPack, taken: {
295
+ entryIds: Iterable<string>;
296
+ presetIds: Iterable<string>;
297
+ }): PackImportResult;
298
+ //# sourceMappingURL=pack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pack.d.ts","sourceRoot":"","sources":["../../src/pack.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Mount-time detection of the tools a machine actually has.
3
+ *
4
+ * A prompt variable's provider is evaluated synchronously on every assembly, so
5
+ * a value that costs a subprocess cannot be computed there: this plugin probes
6
+ * once, when it mounts, and then serves the measured strings from memory.
7
+ *
8
+ * Every probe yields a string. A tool that is absent, one that prints nothing,
9
+ * and one that hangs are all ordinary outcomes, because a variable that resolves
10
+ * to `undefined` makes every section referencing it fail to render — one missing
11
+ * tool would cost the whole system prompt.
12
+ *
13
+ * @module @lolkda/dsh-prompt-manager/probe
14
+ */
15
+ /** Largest number of probes one configuration may declare. */
16
+ export declare const MAX_PROBES = 64;
17
+ /** Per-probe timeout, used when a probe sets no `timeoutMs` of its own. */
18
+ export declare const DEFAULT_PROBE_TIMEOUT_MS = 1500;
19
+ /**
20
+ * Ceiling on the whole probing pass. Reaching it does not fail the mount: the
21
+ * remaining probes report {@link ProbeTexts.skipped} instead, so a command that
22
+ * hangs cannot stall a session's startup.
23
+ */
24
+ export declare const DEFAULT_PROBE_BUDGET_MS = 8000;
25
+ /** Longest value a probe may contribute to the prompt. */
26
+ export declare const MAX_PROBE_VALUE = 120;
27
+ /** What a probe contributes when it cannot contribute a version. */
28
+ export interface ProbeTexts {
29
+ /** The executable could not be started. */
30
+ missing: string;
31
+ /** The executable ran and printed nothing. */
32
+ empty: string;
33
+ /** The executable outlived its timeout. */
34
+ timeout: string;
35
+ /** The pass ran out of budget before this probe started. */
36
+ skipped: string;
37
+ }
38
+ /** Default placeholder texts, in English and machine-independent. */
39
+ export declare const DEFAULT_PROBE_TEXTS: ProbeTexts;
40
+ /** One executable a deployment asks this plugin to detect at mount. */
41
+ export interface ProbeSpec {
42
+ /** Executable name on `PATH`, or an absolute path for a tool outside it. */
43
+ command: string;
44
+ /** Fixed arguments; passed without a shell unless {@link ProbeSpec.shell} is set. */
45
+ args?: string[] | undefined;
46
+ /**
47
+ * Run the command through the platform shell. Needed on Windows for
48
+ * `.cmd`/`.bat` shims such as `npm` and `pnpm`, which cannot be spawned
49
+ * directly.
50
+ */
51
+ shell?: boolean | undefined;
52
+ /**
53
+ * Optional regular expression whose first capture group narrows the value, so
54
+ * `Python 3.12.10` or `git version 2.55.0` can feed a bare `3.12.10`. When it
55
+ * does not match, the untrimmed first line is used instead.
56
+ */
57
+ pattern?: string | undefined;
58
+ /** Timeout for this probe alone, in milliseconds. */
59
+ timeoutMs?: number | undefined;
60
+ }
61
+ /**
62
+ * Probes the built-in machine-environment prompt needs, so a deployment that
63
+ * configures nothing still resolves every `{{...}}` that body references.
64
+ *
65
+ * They are ordinary probes: `config.probes` overrides any of them by name, and
66
+ * `probeDefaults: false` drops them all. Dropping them while the built-in body
67
+ * is still in force leaves its variables unregistered, which fails assembly, so
68
+ * the two settings belong together.
69
+ */
70
+ export declare const DEFAULT_PROBES: Readonly<Record<string, ProbeSpec>>;
71
+ /** What one process run reported, normalized across success and failure. */
72
+ export interface ProbeRun {
73
+ /** `error.code` when the process could not be started at all, e.g. `ENOENT`. */
74
+ spawnError: string | undefined;
75
+ /** Exit code, when the process ran at all. */
76
+ status: number | undefined;
77
+ /** Captured standard output. */
78
+ stdout: string;
79
+ /** Captured standard error; some tools print their version there. */
80
+ stderr: string;
81
+ /** The runner killed the process when its timeout expired. */
82
+ timedOut: boolean;
83
+ }
84
+ /** Runs one probe's command. Replaced in tests, so no real tool is needed. */
85
+ export type ProbeRunner = (command: string, args: string[], options: {
86
+ shell: boolean;
87
+ timeoutMs: number;
88
+ }) => ProbeRun;
89
+ /** One probe's result, as {@link runProbes} reports it. */
90
+ export interface ProbeOutcome {
91
+ /** The variable name this probe feeds. */
92
+ name: string;
93
+ /** The value to register; never empty. */
94
+ value: string;
95
+ /** Wall time this probe took, in milliseconds. */
96
+ ms: number;
97
+ }
98
+ /** The result of a probing pass. */
99
+ export interface ProbeReport {
100
+ /** One outcome per probe that ran or was skipped, in declaration order. */
101
+ outcomes: ProbeOutcome[];
102
+ }
103
+ /**
104
+ * Run a command and collect both streams.
105
+ *
106
+ * `spawnSync` rather than `execFileSync`, because the latter discards standard
107
+ * error on success — and some tools, `java -version` among them, print their
108
+ * version there while exiting zero.
109
+ *
110
+ * @param command - executable name or absolute path.
111
+ * @param args - fixed arguments.
112
+ * @param options - whether to use a shell, and the timeout.
113
+ * @returns the normalized run.
114
+ */
115
+ export declare const defaultProbeRunner: ProbeRunner;
116
+ /**
117
+ * The value one probe contributes.
118
+ * @param spec - the probe to run.
119
+ * @param run - process runner; the real one by default.
120
+ * @param texts - placeholders for the outcomes that carry no version.
121
+ * @returns a non-empty string, whatever happened.
122
+ */
123
+ export declare function probeValue(spec: ProbeSpec, run?: ProbeRunner, texts?: ProbeTexts): string;
124
+ /**
125
+ * Accept the `probes` config value in whatever shape a composition delivers and
126
+ * keep only the specs that can be run.
127
+ *
128
+ * Reports rather than throws: the caller decides whether a malformed probe is a
129
+ * composition error worth failing the mount over.
130
+ *
131
+ * @param raw - the config value.
132
+ * @returns the usable specs, plus one problem message per dropped entry.
133
+ */
134
+ export declare function normalizeProbes(raw: unknown): {
135
+ specs: Record<string, ProbeSpec>;
136
+ problems: string[];
137
+ };
138
+ /**
139
+ * Probe every declared command once, in declaration order.
140
+ * @param specs - usable specs, as {@link normalizeProbes} returns them.
141
+ * @param options - runner, placeholder texts, total budget, and clock.
142
+ * @returns one outcome per probe, none of which can be empty.
143
+ */
144
+ export declare function runProbes(specs: Record<string, ProbeSpec>, options?: {
145
+ run?: ProbeRunner | undefined;
146
+ texts?: ProbeTexts | undefined;
147
+ budgetMs?: number | undefined;
148
+ now?: (() => number) | undefined;
149
+ }): ProbeReport;
150
+ //# sourceMappingURL=probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The browser-facing half of the prompt store: one prefix route carrying the
3
+ * body files the settings page edits.
4
+ *
5
+ * Bodies cannot ride the settings transport, because they are markdown files a
6
+ * person also edits directly. This route is therefore the only write path from
7
+ * the page, and it is fenced twice: loopback peers only, and same-origin
8
+ * requests only for anything that mutates. A stale editor is refused with 409
9
+ * through the hash the page read, so two open drafts cannot silently overwrite
10
+ * each other.
11
+ *
12
+ * Everything else the page edits — the entry index, the presets, the
13
+ * subscriptions, the outbound settings — is a settings field, and this route
14
+ * only fills the gaps that transport leaves: an id nobody holds, a body file, a
15
+ * script on disk, a source's upstream check.
16
+ *
17
+ * @module @lolkda/dsh-prompt-manager/routes
18
+ */
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import type { ResolvedBody } from './entries.js';
21
+ import { PromptStore } from './store.js';
22
+ import { type PromptScripts } from './scripts.js';
23
+ import { type PackApplyResult, type PromptPack } from './pack.js';
24
+ import type { Subscriptions } from './subscriptions.js';
25
+ import type { VariableView } from './index.js';
26
+ /** The single prefix every route below lives under. */
27
+ export declare const ROUTE_PREFIX = "/dsh-prompt-manager";
28
+ /** What the route needs from the plugin that owns the index. */
29
+ export interface PromptRouteHost {
30
+ /** Body files. */
31
+ store: PromptStore;
32
+ /** Effective body for one entry, whichever layer supplies it. */
33
+ describe(id: string): ResolvedBody;
34
+ /** Allocate an unused entry id for a new title. */
35
+ idFor(title: string): string;
36
+ /**
37
+ * Ids the configured presets already hold.
38
+ *
39
+ * The page writes the preset list over the settings transport like it writes
40
+ * the entry index, so the only thing it cannot work out by itself is which id
41
+ * is still free for a new one.
42
+ */
43
+ presetIds(): string[];
44
+ /** Report a non-fatal problem. */
45
+ warn(message: string): void;
46
+ /** The subscription engine, for the source routes. */
47
+ subscriptions: Subscriptions;
48
+ /** The user-script engine, for the variable and script routes. */
49
+ scripts: PromptScripts;
50
+ /**
51
+ * The prompt variables in force, with their provenance and the entries that
52
+ * reference them. Probes and cached script runs are read once at mount, so
53
+ * this is how a deployment checks what is actually being interpolated without
54
+ * making a model step.
55
+ */
56
+ variables(): VariableView[];
57
+ /**
58
+ * The pack for one preset, or `undefined` when no preset here has that id.
59
+ *
60
+ * Built on demand rather than cached: a body can be edited between two
61
+ * exports, and an export that served a stale copy would be worse than one that
62
+ * costs a few file reads.
63
+ */
64
+ packFor(presetId: string): PromptPack | undefined;
65
+ /**
66
+ * Carry out an import.
67
+ *
68
+ * Resolves to what it did, or to why it did nothing — a pack that does not fit
69
+ * or names an unusable body is refused without a single write. A thrown error
70
+ * means the machine was left part-way, and the route reports it as the failure
71
+ * it is.
72
+ */
73
+ importPack(pack: PromptPack): Promise<PackApplyResult>;
74
+ }
75
+ /**
76
+ * Register the prompt-store route.
77
+ *
78
+ * A composition without a web server (the TUI and SDK profiles) simply gets no
79
+ * route; the settings page then reports the store as unreachable.
80
+ *
81
+ * @param ctx - the plugin context whose `webServer` service is injected.
82
+ * @param host - body resolution, id allocation, and logging.
83
+ */
84
+ export declare function installPromptRoutes(ctx: Context, host: PromptRouteHost): void;
85
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAShD,OAAO,EAAY,WAAW,EAAoB,MAAM,YAAY,CAAA;AAKpE,OAAO,EAAe,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAC9D,OAAO,EAA6B,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AAC5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,uDAAuD;AACvD,eAAO,MAAM,YAAY,wBAAwB,CAAA;AAoBjD,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,kBAAkB;IAClB,KAAK,EAAE,WAAW,CAAA;IAClB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAAA;IAClC,mDAAmD;IACnD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B;;;;;;OAMG;IACH,SAAS,IAAI,MAAM,EAAE,CAAA;IACrB,kCAAkC;IAClC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,sDAAsD;IACtD,aAAa,EAAE,aAAa,CAAA;IAC5B,kEAAkE;IAClE,OAAO,EAAE,aAAa,CAAA;IACtB;;;;;OAKG;IACH,SAAS,IAAI,YAAY,EAAE,CAAA;IAC3B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;IACjD;;;;;;;OAOG;IACH,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;CACvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAW7E"}