@stratusagent/cli 0.11.2 → 0.11.4
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/README.md +14 -8
- package/dist/approvals.d.ts +93 -0
- package/dist/approvals.d.ts.map +1 -0
- package/dist/approvals.js +368 -0
- package/dist/approvals.js.map +1 -0
- package/dist/commands/agent-new.d.ts +22 -0
- package/dist/commands/agent-new.d.ts.map +1 -0
- package/dist/commands/agent-new.js +159 -0
- package/dist/commands/agent-new.js.map +1 -0
- package/dist/commands/agents.d.ts +4 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +90 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/chat.d.ts +4 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +227 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/credential.d.ts +22 -0
- package/dist/commands/credential.d.ts.map +1 -0
- package/dist/commands/credential.js +93 -0
- package/dist/commands/credential.js.map +1 -0
- package/dist/commands/dashboard.d.ts +14 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +195 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/doctor.d.ts +40 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +376 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/grants.d.ts +19 -0
- package/dist/commands/grants.d.ts.map +1 -0
- package/dist/commands/grants.js +128 -0
- package/dist/commands/grants.js.map +1 -0
- package/dist/commands/logs.d.ts +9 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +58 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/memory.d.ts +20 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +110 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/plugins.d.ts +103 -0
- package/dist/commands/plugins.d.ts.map +1 -0
- package/dist/commands/plugins.js +386 -0
- package/dist/commands/plugins.js.map +1 -0
- package/dist/commands/restart.d.ts +4 -0
- package/dist/commands/restart.d.ts.map +1 -0
- package/dist/commands/restart.js +25 -0
- package/dist/commands/restart.js.map +1 -0
- package/dist/commands/schedules.d.ts +11 -0
- package/dist/commands/schedules.d.ts.map +1 -0
- package/dist/commands/schedules.js +50 -0
- package/dist/commands/schedules.js.map +1 -0
- package/dist/commands/serve.d.ts +4 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +633 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/service.d.ts +9 -0
- package/dist/commands/service.d.ts.map +1 -0
- package/dist/commands/service.js +97 -0
- package/dist/commands/service.js.map +1 -0
- package/dist/commands/session.d.ts +9 -0
- package/dist/commands/session.d.ts.map +1 -0
- package/dist/commands/session.js +25 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +2467 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/skills.d.ts +15 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +272 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/template.d.ts +4 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +593 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/update.d.ts +21 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +291 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/daemon.d.ts +74 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +192 -0
- package/dist/daemon.js.map +1 -0
- package/dist/environment.d.ts +114 -0
- package/dist/environment.d.ts.map +1 -0
- package/dist/environment.js +2 -0
- package/dist/environment.js.map +1 -0
- package/dist/events.d.ts +17 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +87 -0
- package/dist/events.js.map +1 -0
- package/dist/help.d.ts +2 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +272 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +32 -624
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -6981
- package/dist/index.js.map +1 -1
- package/dist/io.d.ts +16 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +45 -0
- package/dist/io.js.map +1 -0
- package/dist/loaders.d.ts +31 -0
- package/dist/loaders.d.ts.map +1 -0
- package/dist/loaders.js +56 -0
- package/dist/loaders.js.map +1 -0
- package/dist/main.d.ts +8 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +218 -0
- package/dist/main.js.map +1 -0
- package/dist/npm.d.ts +66 -0
- package/dist/npm.d.ts.map +1 -0
- package/dist/npm.js +201 -0
- package/dist/npm.js.map +1 -0
- package/dist/parse.d.ts +245 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +1098 -0
- package/dist/parse.js.map +1 -0
- package/dist/plugin-catalog.d.ts +44 -0
- package/dist/plugin-catalog.d.ts.map +1 -0
- package/dist/plugin-catalog.js +70 -0
- package/dist/plugin-catalog.js.map +1 -0
- package/dist/preflight.d.ts +60 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +102 -0
- package/dist/preflight.js.map +1 -0
- package/dist/prompter.d.ts +84 -0
- package/dist/prompter.d.ts.map +1 -0
- package/dist/prompter.js +347 -0
- package/dist/prompter.js.map +1 -0
- package/dist/roster.d.ts +57 -0
- package/dist/roster.d.ts.map +1 -0
- package/dist/roster.js +78 -0
- package/dist/roster.js.map +1 -0
- package/dist/runtime.d.ts +76 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +372 -0
- package/dist/runtime.js.map +1 -0
- package/dist/slack.d.ts +26 -0
- package/dist/slack.d.ts.map +1 -0
- package/dist/slack.js +113 -0
- package/dist/slack.js.map +1 -0
- package/dist/source.d.ts +24 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +80 -0
- package/dist/source.js.map +1 -0
- package/dist/supervisor.d.ts +69 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +218 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/trusted-config.d.ts +84 -0
- package/dist/trusted-config.d.ts.map +1 -0
- package/dist/trusted-config.js +159 -0
- package/dist/trusted-config.js.map +1 -0
- package/package.json +27 -23
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import { cp, mkdir, mkdtemp, readdir, readFile, rm, stat, unlink, writeFile, } from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
import { escapeControlCharacters } from '@stratusagent/core';
|
|
6
|
+
import { agentsDirPath, globalConfigPath, discoverSkillsInDirectory, installSkillsFromDirectory, declaredAgentIds, loadSoulFile, loadConfigFile, validateConfigFile, saveConfigFile, } from '@stratusagent/state';
|
|
7
|
+
import { writeLine } from "../io.js";
|
|
8
|
+
import { defaultPackageInstaller } from "../npm.js";
|
|
9
|
+
import { resolveSource, redactedSourceUrl, cloneSource } from "../source.js";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Templates: a folder of files, copied into ~/.stratus
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* What a template directory holds. Every entry is a file somebody could
|
|
15
|
+
* have written by hand into `~/.stratus`, which is the whole design:
|
|
16
|
+
* installing one is copying, and reviewing one is reading a folder.
|
|
17
|
+
*
|
|
18
|
+
* template.json name and description — the only required file
|
|
19
|
+
* config.json merged into ~/.stratus/config.json
|
|
20
|
+
* agents/<id>.md soul files, copied to ~/.stratus/agents/
|
|
21
|
+
* skills/<id>/ skill directories, installed exactly as `skill add` does
|
|
22
|
+
*
|
|
23
|
+
* There is deliberately no list of packages to install. The keys of
|
|
24
|
+
* `config.json`'s `plugins` block already name them, and a second list
|
|
25
|
+
* would be a second answer that drifts from the first.
|
|
26
|
+
*/
|
|
27
|
+
const TEMPLATE_MANIFEST_FILENAME = 'template.json';
|
|
28
|
+
const TEMPLATE_CONFIG_FILENAME = 'config.json';
|
|
29
|
+
const TEMPLATE_AGENTS_DIRNAME = 'agents';
|
|
30
|
+
const TEMPLATE_SKILLS_DIRNAME = 'skills';
|
|
31
|
+
/**
|
|
32
|
+
* A package specifier this command will hand to `npm install -g`.
|
|
33
|
+
*
|
|
34
|
+
* `defaultPackageInstaller` spawns npm through a shell on Windows, and its
|
|
35
|
+
* comment says every package name reaching that shell is a constant in
|
|
36
|
+
* this file. A template makes that false — these names come out of a
|
|
37
|
+
* folder somebody downloaded — so anything that is not a plain npm package
|
|
38
|
+
* name is refused before it can be re-parsed as a command. No version
|
|
39
|
+
* suffix either: a template names packages, and the installed version is
|
|
40
|
+
* reported rather than pinned.
|
|
41
|
+
*/
|
|
42
|
+
const NPM_PACKAGE_NAME = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
|
|
43
|
+
const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
44
|
+
/**
|
|
45
|
+
* Merge a template's `config.json` onto the config that exists.
|
|
46
|
+
*
|
|
47
|
+
* Plain objects merge key by key; scalars and arrays replace. That rule is
|
|
48
|
+
* what keeps `plugins` additive — a template naming one package must not
|
|
49
|
+
* take away the packages already enabled, which is exactly the data loss
|
|
50
|
+
* `stratus setup` used to cause.
|
|
51
|
+
*/
|
|
52
|
+
const mergeTemplateConfig = (base, incoming) => {
|
|
53
|
+
if (!isPlainObject(base) || !isPlainObject(incoming)) {
|
|
54
|
+
return incoming;
|
|
55
|
+
}
|
|
56
|
+
const merged = { ...base };
|
|
57
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
58
|
+
merged[key] = mergeTemplateConfig(base[key], value);
|
|
59
|
+
}
|
|
60
|
+
return merged;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* The document a template's config would produce, refused if the loader
|
|
64
|
+
* would refuse it.
|
|
65
|
+
*
|
|
66
|
+
* `validateConfigFile` exists for this — "anything that *writes* a config
|
|
67
|
+
* has to answer the same question the loader answers", says its own doc
|
|
68
|
+
* comment — and a template's `config.json` is only checked for being an
|
|
69
|
+
* object, so `plugins: []` or `api: { port: "bad" }` would otherwise be
|
|
70
|
+
* written and make the whole global config unreadable on the next run.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* Fragment leaves the validated document does not carry, by dotted path.
|
|
74
|
+
*
|
|
75
|
+
* `validateConfigFile` normalizes: it builds a fresh document out of the
|
|
76
|
+
* fields it recognizes, so a top-level key of the wrong type is dropped
|
|
77
|
+
* rather than refused. `model: 123` over an existing `model: "sonnet"`
|
|
78
|
+
* therefore deletes the model, while the review says it sets it to 123 and
|
|
79
|
+
* the command reports success. Saving only what survives is right; saving
|
|
80
|
+
* it without saying what did not is the bug.
|
|
81
|
+
*/
|
|
82
|
+
const leavesNotApplied = (fragment, validated, prefix = []) => {
|
|
83
|
+
if (!isPlainObject(fragment)) {
|
|
84
|
+
return JSON.stringify(validated) === JSON.stringify(fragment) ? [] : [prefix.join('.')];
|
|
85
|
+
}
|
|
86
|
+
// An empty object asks for a block, not for emptiness: the merge leaves
|
|
87
|
+
// whatever was already there, so anything object-shaped satisfies it.
|
|
88
|
+
if (!isPlainObject(validated)) {
|
|
89
|
+
return [prefix.join('.')];
|
|
90
|
+
}
|
|
91
|
+
return Object.entries(fragment)
|
|
92
|
+
.flatMap(([key, child]) => leavesNotApplied(child, validated[key], [...prefix, key]));
|
|
93
|
+
};
|
|
94
|
+
const mergedTemplateConfig = (current, fragment, configPath) => {
|
|
95
|
+
const merged = mergeTemplateConfig(current, fragment);
|
|
96
|
+
let validated;
|
|
97
|
+
try {
|
|
98
|
+
validated = validateConfigFile(merged, configPath);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
throw new Error(`This template's ${TEMPLATE_CONFIG_FILENAME} would make ${configPath} unreadable: `
|
|
102
|
+
+ `${error instanceof Error ? error.message : String(error)}`);
|
|
103
|
+
}
|
|
104
|
+
const dropped = leavesNotApplied(fragment, validated);
|
|
105
|
+
if (dropped.length > 0) {
|
|
106
|
+
throw new Error(`This template's ${TEMPLATE_CONFIG_FILENAME} sets ${dropped.map(fromTemplate).join(', ')}, `
|
|
107
|
+
+ `which ${configPath} cannot hold — the wrong type, or not a setting at all. `
|
|
108
|
+
+ 'Installing it would drop those keys while the review said it set them, '
|
|
109
|
+
+ 'and a key you already had set would go with them. Fix the template.');
|
|
110
|
+
}
|
|
111
|
+
return validated;
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Every value a config fragment actually sets, as a dotted path.
|
|
115
|
+
*
|
|
116
|
+
* The review used to print the top-level keys — `config plugins` — which
|
|
117
|
+
* says nothing about what changed. A fragment's capability lives in its
|
|
118
|
+
* leaves: `plugins.@stratusagent/tool-fs.roots` is the difference between
|
|
119
|
+
* reading `~/notes` and reading `/`, and a review that hides it is a
|
|
120
|
+
* review that can be used to smuggle one past an operator.
|
|
121
|
+
*
|
|
122
|
+
* An empty object is a leaf in its own right: `{ plugins: { pkg: {} } }`
|
|
123
|
+
* adds a block, and printing nothing for it would lose that too.
|
|
124
|
+
*/
|
|
125
|
+
const configLeaves = (value, current, prefix = []) => {
|
|
126
|
+
if (!isPlainObject(value) || Object.keys(value).length === 0) {
|
|
127
|
+
const replaced = current !== undefined && JSON.stringify(current) !== JSON.stringify(value);
|
|
128
|
+
return [{ path: prefix.join('.'), value, ...(replaced ? { was: current } : {}) }];
|
|
129
|
+
}
|
|
130
|
+
// The current value is walked alongside rather than looked up by the
|
|
131
|
+
// dotted path afterwards: npm names may contain dots, so `plugins` plus
|
|
132
|
+
// a key like `a.b` renders a path that does not parse back to the key it
|
|
133
|
+
// came from — and a "replaces" note naming the wrong value would be
|
|
134
|
+
// worse than none.
|
|
135
|
+
return Object.entries(value).flatMap(([key, child]) => configLeaves(child, isPlainObject(current) ? current[key] : undefined, [...prefix, key]));
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* Whether the soul already at `destination` is itself the holder of `id`.
|
|
139
|
+
* A match is the ordinary `--force` replacement rather than a collision with
|
|
140
|
+
* somebody else's agent; an unreadable or absent file is not holding it.
|
|
141
|
+
*/
|
|
142
|
+
const destinationHoldsId = async (destination, id) => {
|
|
143
|
+
try {
|
|
144
|
+
return (await loadSoulFile(destination)).agent.id === id;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const readTemplateJson = async (file) => {
|
|
151
|
+
let raw;
|
|
152
|
+
try {
|
|
153
|
+
raw = await readFile(file, 'utf8');
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error.code === 'ENOENT') {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
let parsed;
|
|
162
|
+
try {
|
|
163
|
+
parsed = JSON.parse(raw);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw new Error(`${file} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
167
|
+
}
|
|
168
|
+
if (!isPlainObject(parsed)) {
|
|
169
|
+
throw new Error(`${file} must contain a JSON object.`);
|
|
170
|
+
}
|
|
171
|
+
return parsed;
|
|
172
|
+
};
|
|
173
|
+
/** Read a template directory and work out what installing it would do. */
|
|
174
|
+
const planTemplateInstall = async (env, directory, warn) => {
|
|
175
|
+
const manifest = await readTemplateJson(path.join(directory, TEMPLATE_MANIFEST_FILENAME));
|
|
176
|
+
if (!manifest) {
|
|
177
|
+
throw new Error(`${directory} has no ${TEMPLATE_MANIFEST_FILENAME}, so it is not a template. `
|
|
178
|
+
+ 'A template is a directory with template.json in it; see docs/guides/templates.md.');
|
|
179
|
+
}
|
|
180
|
+
const name = typeof manifest.name === 'string' ? manifest.name.trim() : '';
|
|
181
|
+
const description = typeof manifest.description === 'string' ? manifest.description.trim() : '';
|
|
182
|
+
if (!name || !description) {
|
|
183
|
+
throw new Error(`${path.join(directory, TEMPLATE_MANIFEST_FILENAME)} needs a "name" and a "description".`);
|
|
184
|
+
}
|
|
185
|
+
const config = await readTemplateJson(path.join(directory, TEMPLATE_CONFIG_FILENAME)) ?? {};
|
|
186
|
+
const pluginsBlock = config.plugins;
|
|
187
|
+
const packages = isPlainObject(pluginsBlock) ? Object.keys(pluginsBlock) : [];
|
|
188
|
+
for (const specifier of packages) {
|
|
189
|
+
if (!NPM_PACKAGE_NAME.test(specifier)) {
|
|
190
|
+
throw new Error(`${JSON.stringify(specifier)} is not an npm package name, so this template will not be installed. `
|
|
191
|
+
+ 'A plugins key names the package to install and enable, nothing else.');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// What this install would have to fetch. Resolved the way the daemon
|
|
195
|
+
// resolves a plugin, so "already installed" means the same thing here as
|
|
196
|
+
// it does when the plugin is loaded.
|
|
197
|
+
const missing = packages.filter((specifier) => {
|
|
198
|
+
try {
|
|
199
|
+
import.meta.resolve(specifier);
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
const agents = [];
|
|
207
|
+
const agentsDir = path.join(directory, TEMPLATE_AGENTS_DIRNAME);
|
|
208
|
+
let agentFiles = [];
|
|
209
|
+
try {
|
|
210
|
+
agentFiles = (await readdir(agentsDir, { withFileTypes: true }))
|
|
211
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
|
|
212
|
+
.map((entry) => entry.name)
|
|
213
|
+
.sort((left, right) => left.localeCompare(right));
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (error.code !== 'ENOENT') {
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// The ids already spoken for, by path, so a soul whose id matches the very
|
|
221
|
+
// file it would replace is the ordinary `--force` case rather than a
|
|
222
|
+
// collision. A roster that is already broken is warned about and skipped:
|
|
223
|
+
// this command is not the place to refuse over somebody else's duplicate.
|
|
224
|
+
// `declaredAgentIds`, not a roster read of this command's own: it is the
|
|
225
|
+
// set an id is actually claimed against — the roster, the configured
|
|
226
|
+
// default soul (which can live outside `agents/` and still be served),
|
|
227
|
+
// and the built-in `stratus`. Reading the roster alone said "available"
|
|
228
|
+
// for ids the daemon would then hand to somebody else.
|
|
229
|
+
// Pinned to the global config, because that is the one this command
|
|
230
|
+
// merges into. Unpinned, `declaredAgentIds` resolves the configured soul
|
|
231
|
+
// by the working directory's precedence, so a checkout carrying a
|
|
232
|
+
// `stratus.config.json` hides the global config's own `soul:` — and an id
|
|
233
|
+
// that soul holds is then claimed against the wrong set, installing a
|
|
234
|
+
// roster entry the daemon shadows.
|
|
235
|
+
const declared = agentFiles.length > 0
|
|
236
|
+
? await declaredAgentIds(env, globalConfigPath(env))
|
|
237
|
+
: { ids: new Set(), unread: [] };
|
|
238
|
+
if (declared.unread.length > 0) {
|
|
239
|
+
warn(`could not read ${declared.unread.join(' or ')}, so ids were not checked against what it declares.`);
|
|
240
|
+
}
|
|
241
|
+
const claimedHere = new Map();
|
|
242
|
+
for (const file of agentFiles) {
|
|
243
|
+
// Parsed rather than copied blind: the review below can only name the
|
|
244
|
+
// agent and its tools if the soul actually reads, and a template
|
|
245
|
+
// shipping a broken one should fail here rather than at the next run.
|
|
246
|
+
const soulPath = path.join(agentsDir, file);
|
|
247
|
+
const soul = await loadSoulFile(soulPath);
|
|
248
|
+
// The bytes the review is about, kept rather than re-read at copy time:
|
|
249
|
+
// a local template is a directory something else can edit, and the gap
|
|
250
|
+
// between the prompt and the copy is however long a human takes. What
|
|
251
|
+
// lands has to be what was shown.
|
|
252
|
+
const contents = await readFile(soulPath, 'utf8');
|
|
253
|
+
const destination = path.join(agentsDirPath(env), file);
|
|
254
|
+
let taken = false;
|
|
255
|
+
try {
|
|
256
|
+
await stat(destination);
|
|
257
|
+
taken = true;
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Not installed under this name.
|
|
261
|
+
}
|
|
262
|
+
const replacesOwnId = taken && await destinationHoldsId(destination, soul.agent.id);
|
|
263
|
+
const alsoHere = claimedHere.get(soul.agent.id);
|
|
264
|
+
const blocked = alsoHere !== undefined
|
|
265
|
+
? `${alsoHere} in this template already claims the id ${soul.agent.id}`
|
|
266
|
+
: !replacesOwnId && declared.ids.has(soul.agent.id)
|
|
267
|
+
? `something already claims the id ${soul.agent.id}`
|
|
268
|
+
: undefined;
|
|
269
|
+
claimedHere.set(soul.agent.id, file);
|
|
270
|
+
agents.push({
|
|
271
|
+
file,
|
|
272
|
+
contents,
|
|
273
|
+
id: soul.agent.id,
|
|
274
|
+
name: soul.agent.name,
|
|
275
|
+
tools: soul.agent.tools ? [...soul.agent.tools] : undefined,
|
|
276
|
+
credentials: soul.agent.credentials ? [...soul.agent.credentials] : undefined,
|
|
277
|
+
delegates: soul.agent.delegates ? [...soul.agent.delegates] : undefined,
|
|
278
|
+
taken,
|
|
279
|
+
...(blocked !== undefined ? { blocked } : {}),
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
// Discovered by the same call that will install them. A directory listing
|
|
283
|
+
// is a different rule: `discoverSkillsInDirectory` also finds a root
|
|
284
|
+
// `SKILL.md` and the nested `.claude/skills/` layout, so a listing here
|
|
285
|
+
// would omit skills the installer then adds — the review under-reporting
|
|
286
|
+
// what lands, which is the one thing it must not do.
|
|
287
|
+
const skills = (await discoverSkillsInDirectory(path.join(directory, TEMPLATE_SKILLS_DIRNAME)))
|
|
288
|
+
.candidates
|
|
289
|
+
.map((candidate) => candidate.id)
|
|
290
|
+
.sort((left, right) => left.localeCompare(right));
|
|
291
|
+
// Validated against the config as it stands, so a fragment the loader
|
|
292
|
+
// would reject refuses the whole command before a single file is copied.
|
|
293
|
+
// Checked again under the write below, in case the file moved underneath.
|
|
294
|
+
const configChanges = [];
|
|
295
|
+
if (Object.keys(config).length > 0) {
|
|
296
|
+
let current = {};
|
|
297
|
+
try {
|
|
298
|
+
current = await loadConfigFile(globalConfigPath(env));
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
if (error.code !== 'ENOENT') {
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
mergedTemplateConfig(current, config, globalConfigPath(env));
|
|
306
|
+
configChanges.push(...configLeaves(config, current));
|
|
307
|
+
}
|
|
308
|
+
return { name, description, directory, agents, skills, packages, missing, config, configChanges };
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Text a template supplied, on its way to a terminal.
|
|
312
|
+
*
|
|
313
|
+
* Every string in the review comes out of a folder somebody downloaded —
|
|
314
|
+
* the manifest, agent and tool names, config keys, filenames. A key ending
|
|
315
|
+
* in `\u001b[2J` erases the review directly above the prompt, and the
|
|
316
|
+
* operator then approves a display the template wrote. `JSON.stringify`
|
|
317
|
+
* covers a value's C0 range and nothing else, so it is not the guard
|
|
318
|
+
* either. This is the rule `stratus memory list` already applies to
|
|
319
|
+
* untrusted text, for the same reason.
|
|
320
|
+
*/
|
|
321
|
+
const fromTemplate = (text) => escapeControlCharacters(text);
|
|
322
|
+
/**
|
|
323
|
+
* An id as the review prints it in a comma-separated list. An id may itself
|
|
324
|
+
* contain a comma or a space — the validator allows both — and a review
|
|
325
|
+
* that printed `editor, reviewer` for one grant to the agent `editor, reviewer`
|
|
326
|
+
* and for two grants alike would be a security review that cannot be read.
|
|
327
|
+
* Such an id is JSON-quoted; a plain one stays plain.
|
|
328
|
+
*/
|
|
329
|
+
const reviewId = (id) => (/[,\s"']/.test(id) ? JSON.stringify(id) : id);
|
|
330
|
+
/** What the operator says yes to: every file this would add, and every package. */
|
|
331
|
+
const writeTemplatePlan = (streams, plan, env) => {
|
|
332
|
+
writeLine(streams.stdout, `${fromTemplate(plan.name)} — ${fromTemplate(plan.description)}`);
|
|
333
|
+
writeLine(streams.stdout);
|
|
334
|
+
for (const agent of plan.agents) {
|
|
335
|
+
// An absent `tools:` is not "none", it is "all" — see TemplateAgentPlan.
|
|
336
|
+
const tools = agent.tools === undefined
|
|
337
|
+
? 'EVERY tool, because the soul has no tools: list'
|
|
338
|
+
: agent.tools.length > 0 ? fromTemplate(agent.tools.join(', ')) : 'no tools';
|
|
339
|
+
writeLine(streams.stdout, ` agent ${fromTemplate(agent.name)} (${fromTemplate(agent.id)}) — ${tools}`);
|
|
340
|
+
// The other gate, and the one nobody expects a folder of markdown to
|
|
341
|
+
// move: a name here reaches the stored secret of that name the moment
|
|
342
|
+
// the soul lands. Printed on its own line rather than appended to the
|
|
343
|
+
// tools, because it is a different kind of grant.
|
|
344
|
+
if (agent.credentials !== undefined && agent.credentials.length > 0) {
|
|
345
|
+
writeLine(streams.stdout, ` may read your stored credentials: ${fromTemplate(agent.credentials.join(', '))}`);
|
|
346
|
+
}
|
|
347
|
+
// The furthest-reaching grant a folder of markdown can carry: a target
|
|
348
|
+
// runs a turn as that agent, under that agent's tools, credentials, and
|
|
349
|
+
// memory, and the wildcard is the whole roster — including agents this
|
|
350
|
+
// template never saw. Said in those words, like the empty tools: list.
|
|
351
|
+
if (agent.delegates !== undefined && agent.delegates.length > 0) {
|
|
352
|
+
writeLine(streams.stdout, agent.delegates.includes('*')
|
|
353
|
+
? ' may hand work to EVERY agent on your roster, and run as them (delegates: [*])'
|
|
354
|
+
: ` may hand work to, and run as: ${fromTemplate(agent.delegates.map(reviewId).join(', '))}`);
|
|
355
|
+
}
|
|
356
|
+
if (agent.blocked !== undefined) {
|
|
357
|
+
writeLine(streams.stdout, ` cannot install ${fromTemplate(agent.file)}: ${fromTemplate(agent.blocked)}.`);
|
|
358
|
+
}
|
|
359
|
+
else if (agent.taken) {
|
|
360
|
+
writeLine(streams.stdout, ` ${fromTemplate(agent.file)} is already in your roster; --force replaces it.`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
for (const skill of plan.skills) {
|
|
364
|
+
writeLine(streams.stdout, ` skill ${fromTemplate(skill)}`);
|
|
365
|
+
}
|
|
366
|
+
for (const specifier of plan.packages) {
|
|
367
|
+
const note = plan.missing.includes(specifier) ? 'npm install -g' : 'already installed';
|
|
368
|
+
writeLine(streams.stdout, ` plugin ${fromTemplate(specifier)} (${note})`);
|
|
369
|
+
}
|
|
370
|
+
if (plan.configChanges.length > 0) {
|
|
371
|
+
writeLine(streams.stdout, ` config ${globalConfigPath(env)}`);
|
|
372
|
+
for (const change of plan.configChanges) {
|
|
373
|
+
const replaces = change.was !== undefined ? ` (replaces ${fromTemplate(JSON.stringify(change.was))})` : '';
|
|
374
|
+
writeLine(streams.stdout, ` ${fromTemplate(change.path)}: ${fromTemplate(JSON.stringify(change.value))}${replaces}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
writeLine(streams.stdout);
|
|
378
|
+
};
|
|
379
|
+
/** A y/N on stderr, so stdout stays exactly what `--yes` would have printed. */
|
|
380
|
+
const confirmTemplateInstall = async (streams, env) => {
|
|
381
|
+
const input = env.templateInput ?? process.stdin;
|
|
382
|
+
const readline = createInterface({ input, terminal: false });
|
|
383
|
+
streams.stderr.write('Install this? [y/N] ');
|
|
384
|
+
try {
|
|
385
|
+
const answer = await new Promise((resolve) => {
|
|
386
|
+
readline.once('line', resolve);
|
|
387
|
+
readline.once('close', () => resolve(''));
|
|
388
|
+
});
|
|
389
|
+
writeLine(streams.stderr);
|
|
390
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
391
|
+
}
|
|
392
|
+
finally {
|
|
393
|
+
readline.close();
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
export const runTemplateAdd = async (command, streams, env = {}) => {
|
|
397
|
+
const resolved = await resolveSource(command.source, env, 'template');
|
|
398
|
+
// Everything is read from a directory nothing else can write, so what the
|
|
399
|
+
// review described is what installs. A clone is already private; a local
|
|
400
|
+
// path is not — it is a working copy somebody may be editing, and the gap
|
|
401
|
+
// between printing the review and copying is however long the operator
|
|
402
|
+
// takes to answer plus however long `npm install -g` runs.
|
|
403
|
+
const scratch = await mkdtemp(path.join(os.tmpdir(), 'stratus-template-add-'));
|
|
404
|
+
const cleanup = () => rm(scratch, { recursive: true, force: true });
|
|
405
|
+
const directory = scratch;
|
|
406
|
+
try {
|
|
407
|
+
if (resolved.kind === 'local') {
|
|
408
|
+
// verbatimSymlinks for the reason `installSkillsFromDirectory` uses it
|
|
409
|
+
// on its own staging copy: the default rewrites a relative link to an
|
|
410
|
+
// absolute path into the source tree, and `findEscapingSymlink` then
|
|
411
|
+
// reads a skill's own intra-skill link as reaching outside itself and
|
|
412
|
+
// skips the skill. Installing the same folder through `skill add`
|
|
413
|
+
// accepts it, so the snapshot must not change the answer.
|
|
414
|
+
await cp(resolved.directory, scratch, { recursive: true, verbatimSymlinks: true });
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
writeLine(streams.stdout, `Fetching ${redactedSourceUrl(resolved.url)} …`);
|
|
418
|
+
await cloneSource(resolved.url, scratch);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
await cleanup();
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
const plan = await planTemplateInstall(env, directory, (line) => writeLine(streams.stderr, `Warning: ${fromTemplate(line)}`));
|
|
427
|
+
writeTemplatePlan(streams, plan, env);
|
|
428
|
+
if (!command.yes && !await confirmTemplateInstall(streams, env)) {
|
|
429
|
+
writeLine(streams.stderr, 'Nothing was installed.');
|
|
430
|
+
return 1;
|
|
431
|
+
}
|
|
432
|
+
// Packages first, config last. A package installed with nothing
|
|
433
|
+
// enabling it is inert; a config enabling a package that is not
|
|
434
|
+
// installed makes the daemon warn and skip it on every start.
|
|
435
|
+
if (plan.missing.length > 0) {
|
|
436
|
+
const installer = env.packageInstaller ?? defaultPackageInstaller;
|
|
437
|
+
const result = await installer(plan.missing);
|
|
438
|
+
if (!result.ok) {
|
|
439
|
+
writeLine(streams.stderr, `Could not install ${plan.missing.join(' ')}: ${result.message}`);
|
|
440
|
+
writeLine(streams.stderr, 'Nothing was installed.');
|
|
441
|
+
return 1;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
await mkdir(agentsDirPath(env), { recursive: true });
|
|
445
|
+
// Re-read the claimed ids rather than trusting the plan's snapshot. The
|
|
446
|
+
// exclusive write below only catches a collision on the same *path*, and
|
|
447
|
+
// an id is claimed by content: another `template add`, an `agent new`, or
|
|
448
|
+
// a hand-edited soul can take one under a different filename while the
|
|
449
|
+
// review sits at its prompt. Two files with one id is what
|
|
450
|
+
// `loadRosterSouls` refuses, and it refuses the whole roster. This
|
|
451
|
+
// narrows the window rather than closing it — the same gap between the
|
|
452
|
+
// read and the write that `stratus agent new` has.
|
|
453
|
+
const claimedNow = plan.agents.length > 0
|
|
454
|
+
? await declaredAgentIds(env, globalConfigPath(env))
|
|
455
|
+
: { ids: new Set() };
|
|
456
|
+
const installedAgents = [];
|
|
457
|
+
const enabledPackages = [];
|
|
458
|
+
const refusedAgents = [];
|
|
459
|
+
const blockedAgents = [];
|
|
460
|
+
for (const agent of plan.agents) {
|
|
461
|
+
const destination = path.join(agentsDirPath(env), agent.file);
|
|
462
|
+
// Never, with or without --force: two files claiming one id is what
|
|
463
|
+
// `loadRosterSouls` refuses, and it refuses the whole roster.
|
|
464
|
+
if (agent.blocked !== undefined) {
|
|
465
|
+
blockedAgents.push(`${agent.file} — ${agent.blocked}`);
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (claimedNow.ids.has(agent.id) && !await destinationHoldsId(destination, agent.id)) {
|
|
469
|
+
blockedAgents.push(`${agent.file} — something already claims the id ${agent.id}`);
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (agent.taken && !command.force) {
|
|
473
|
+
refusedAgents.push(agent.file);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
try {
|
|
477
|
+
// `--force` removes the entry first rather than writing over it: a
|
|
478
|
+
// roster entry can be a symlink, and writing through one truncates
|
|
479
|
+
// whatever it points at — a file outside the agents directory that
|
|
480
|
+
// this command was never asked to touch. `unlink` removes the link
|
|
481
|
+
// itself, so a dangling one is replaced too.
|
|
482
|
+
if (command.force) {
|
|
483
|
+
try {
|
|
484
|
+
await unlink(destination);
|
|
485
|
+
}
|
|
486
|
+
catch (error) {
|
|
487
|
+
if (error.code !== 'ENOENT') {
|
|
488
|
+
throw error;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// Always exclusive, both paths: the destination was checked while
|
|
493
|
+
// planning, and another `template add`, a setup flow, or an editor
|
|
494
|
+
// can create it in the meantime. Without the flag the documented
|
|
495
|
+
// "refused without --force" quietly becomes an overwrite of
|
|
496
|
+
// somebody's newer file, and a forced write lands on a file created
|
|
497
|
+
// after the unlink.
|
|
498
|
+
await writeFile(destination, agent.contents, { flag: 'wx' });
|
|
499
|
+
}
|
|
500
|
+
catch (error) {
|
|
501
|
+
if (error.code !== 'EEXIST') {
|
|
502
|
+
throw error;
|
|
503
|
+
}
|
|
504
|
+
refusedAgents.push(agent.file);
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
installedAgents.push(`${fromTemplate(agent.name)} (${fromTemplate(agent.id)})`);
|
|
508
|
+
}
|
|
509
|
+
// The same installer `skill add` uses, so a skill a template carries
|
|
510
|
+
// and a skill installed by hand land identically — including the
|
|
511
|
+
// refuse-rather-than-overwrite rule.
|
|
512
|
+
const skillResult = plan.skills.length > 0
|
|
513
|
+
? await installSkillsFromDirectory(env, path.join(directory, TEMPLATE_SKILLS_DIRNAME), {
|
|
514
|
+
...(command.force ? { force: true } : {}),
|
|
515
|
+
})
|
|
516
|
+
: { installed: [], skipped: [], warnings: [], alreadyInstalled: [] };
|
|
517
|
+
if (Object.keys(plan.config).length > 0) {
|
|
518
|
+
const configPath = globalConfigPath(env);
|
|
519
|
+
let current = {};
|
|
520
|
+
try {
|
|
521
|
+
current = await loadConfigFile(configPath);
|
|
522
|
+
}
|
|
523
|
+
catch (error) {
|
|
524
|
+
if (error.code !== 'ENOENT') {
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
const merged = mergedTemplateConfig(current, plan.config, configPath);
|
|
529
|
+
await saveConfigFile(configPath, merged);
|
|
530
|
+
// What the merged block says, not what the template asked for. A
|
|
531
|
+
// fragment carrying `enabled: false`, or one that says nothing about
|
|
532
|
+
// `enabled` over a block already disabled, leaves the plugin off —
|
|
533
|
+
// and "enabled X" would then be the command reporting a capability
|
|
534
|
+
// the next restart will not provide.
|
|
535
|
+
for (const specifier of plan.packages) {
|
|
536
|
+
const block = merged.plugins?.[specifier];
|
|
537
|
+
enabledPackages.push({ specifier, on: block?.enabled !== false });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
for (const agent of installedAgents) {
|
|
541
|
+
writeLine(streams.stdout, `installed ${agent}`);
|
|
542
|
+
}
|
|
543
|
+
for (const skill of skillResult.installed) {
|
|
544
|
+
writeLine(streams.stdout, `installed skill ${fromTemplate(skill.id)}`);
|
|
545
|
+
}
|
|
546
|
+
const enabled = enabledPackages.filter((entry) => entry.on).map((entry) => entry.specifier);
|
|
547
|
+
const stillOff = enabledPackages.filter((entry) => !entry.on).map((entry) => entry.specifier);
|
|
548
|
+
if (enabled.length > 0) {
|
|
549
|
+
writeLine(streams.stdout, `enabled ${fromTemplate(enabled.join(', '))} in ${globalConfigPath(env)}`);
|
|
550
|
+
}
|
|
551
|
+
for (const specifier of stillOff) {
|
|
552
|
+
writeLine(streams.stdout, `configured ${fromTemplate(specifier)} in ${globalConfigPath(env)}, still disabled`);
|
|
553
|
+
}
|
|
554
|
+
// Warnings rather than failures, on stderr, for the reason `skill add`
|
|
555
|
+
// puts its own there: the rest of the template installed, and stdout is
|
|
556
|
+
// the record of what landed. Only a template that added nothing at all
|
|
557
|
+
// is an error.
|
|
558
|
+
for (const file of refusedAgents) {
|
|
559
|
+
writeLine(streams.stderr, command.force
|
|
560
|
+
? `Warning: skipped ${fromTemplate(file)} — something created it while this was installing. Run the same command again to replace it.`
|
|
561
|
+
: `Warning: skipped ${fromTemplate(file)} — an agent of that name is already in your roster (--force replaces it).`);
|
|
562
|
+
}
|
|
563
|
+
for (const blocked of blockedAgents) {
|
|
564
|
+
writeLine(streams.stderr, `Warning: skipped ${fromTemplate(blocked)}. Ids key sessions, memory, and credentials, so one of them has to change.`);
|
|
565
|
+
}
|
|
566
|
+
for (const skipped of skillResult.skipped) {
|
|
567
|
+
writeLine(streams.stderr, `Warning: skipped skill ${fromTemplate(skipped.id)}: ${fromTemplate(skipped.reason)}`);
|
|
568
|
+
}
|
|
569
|
+
// What installed *with* a caveat — a field another host owns, a bundled
|
|
570
|
+
// scripts/ — said the same way `skill add` says it. The operator
|
|
571
|
+
// deciding whether to enable a skill is the one who needs to hear it,
|
|
572
|
+
// and a template installs skills without their asking for each.
|
|
573
|
+
for (const warning of skillResult.warnings) {
|
|
574
|
+
writeLine(streams.stderr, `Warning: ${fromTemplate(warning.id)}: ${fromTemplate(warning.message)}`);
|
|
575
|
+
}
|
|
576
|
+
if (installedAgents.length === 0 && skillResult.installed.length === 0 && Object.keys(plan.config).length === 0) {
|
|
577
|
+
writeLine(streams.stderr, 'Error: nothing was installed.');
|
|
578
|
+
return 1;
|
|
579
|
+
}
|
|
580
|
+
// A running daemon holds its roster and its plugins in memory: souls are
|
|
581
|
+
// re-read only for agents it already has, and a plugin is loaded at
|
|
582
|
+
// start. So anything that landed needs the announced restart before it
|
|
583
|
+
// is served — not only a plugin change.
|
|
584
|
+
writeLine(streams.stdout);
|
|
585
|
+
writeLine(streams.stdout, 'Tell a running daemon about it:');
|
|
586
|
+
writeLine(streams.stdout, ' stratus restart # picks up new agents, skills, and plugins');
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
await cleanup();
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../src/commands/template.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CliStreams, CliEnvironment } from '../environment.ts';
|
|
2
|
+
import type { ParsedUpdateCommand } from '../parse.ts';
|
|
3
|
+
/**
|
|
4
|
+
* `stratus update` — the whole upgrade dance, in the order that cannot lose
|
|
5
|
+
* data: stop the service (so no daemon holds the session database while
|
|
6
|
+
* state migrates), upgrade the package, run pending migrations, rewrite the
|
|
7
|
+
* service unit with current paths, restart.
|
|
8
|
+
*
|
|
9
|
+
* The unit rewrite is the step that repairs the failure nothing else
|
|
10
|
+
* surfaces: the unit embeds absolute node and entrypoint paths (a service
|
|
11
|
+
* manager loads no shell profile, so it must), and upgrading node — under
|
|
12
|
+
* nvm, a whole new version directory — leaves the unit pointing at an
|
|
13
|
+
* interpreter that no longer exists. The service stops working and nothing
|
|
14
|
+
* says so; the agents just stop answering.
|
|
15
|
+
*
|
|
16
|
+
* Each step degrades independently: an unreachable npm skips the version
|
|
17
|
+
* check and package upgrade but still migrates and rewrites the unit —
|
|
18
|
+
* which is exactly the repair the offline case needs.
|
|
19
|
+
*/
|
|
20
|
+
export declare const runUpdate: (command: ParsedUpdateCommand, streams: CliStreams, env: CliEnvironment) => Promise<number>;
|
|
21
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AA6CvD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,SAAS,GACpB,SAAS,mBAAmB,EAC5B,SAAS,UAAU,EACnB,KAAK,cAAc,KAClB,OAAO,CAAC,MAAM,CAuPhB,CAAC"}
|