@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.
Files changed (158) hide show
  1. package/README.md +14 -8
  2. package/dist/approvals.d.ts +93 -0
  3. package/dist/approvals.d.ts.map +1 -0
  4. package/dist/approvals.js +368 -0
  5. package/dist/approvals.js.map +1 -0
  6. package/dist/commands/agent-new.d.ts +22 -0
  7. package/dist/commands/agent-new.d.ts.map +1 -0
  8. package/dist/commands/agent-new.js +159 -0
  9. package/dist/commands/agent-new.js.map +1 -0
  10. package/dist/commands/agents.d.ts +4 -0
  11. package/dist/commands/agents.d.ts.map +1 -0
  12. package/dist/commands/agents.js +90 -0
  13. package/dist/commands/agents.js.map +1 -0
  14. package/dist/commands/chat.d.ts +4 -0
  15. package/dist/commands/chat.d.ts.map +1 -0
  16. package/dist/commands/chat.js +227 -0
  17. package/dist/commands/chat.js.map +1 -0
  18. package/dist/commands/credential.d.ts +22 -0
  19. package/dist/commands/credential.d.ts.map +1 -0
  20. package/dist/commands/credential.js +93 -0
  21. package/dist/commands/credential.js.map +1 -0
  22. package/dist/commands/dashboard.d.ts +14 -0
  23. package/dist/commands/dashboard.d.ts.map +1 -0
  24. package/dist/commands/dashboard.js +195 -0
  25. package/dist/commands/dashboard.js.map +1 -0
  26. package/dist/commands/doctor.d.ts +40 -0
  27. package/dist/commands/doctor.d.ts.map +1 -0
  28. package/dist/commands/doctor.js +376 -0
  29. package/dist/commands/doctor.js.map +1 -0
  30. package/dist/commands/grants.d.ts +19 -0
  31. package/dist/commands/grants.d.ts.map +1 -0
  32. package/dist/commands/grants.js +128 -0
  33. package/dist/commands/grants.js.map +1 -0
  34. package/dist/commands/logs.d.ts +9 -0
  35. package/dist/commands/logs.d.ts.map +1 -0
  36. package/dist/commands/logs.js +58 -0
  37. package/dist/commands/logs.js.map +1 -0
  38. package/dist/commands/memory.d.ts +20 -0
  39. package/dist/commands/memory.d.ts.map +1 -0
  40. package/dist/commands/memory.js +110 -0
  41. package/dist/commands/memory.js.map +1 -0
  42. package/dist/commands/plugins.d.ts +103 -0
  43. package/dist/commands/plugins.d.ts.map +1 -0
  44. package/dist/commands/plugins.js +386 -0
  45. package/dist/commands/plugins.js.map +1 -0
  46. package/dist/commands/restart.d.ts +4 -0
  47. package/dist/commands/restart.d.ts.map +1 -0
  48. package/dist/commands/restart.js +25 -0
  49. package/dist/commands/restart.js.map +1 -0
  50. package/dist/commands/schedules.d.ts +11 -0
  51. package/dist/commands/schedules.d.ts.map +1 -0
  52. package/dist/commands/schedules.js +50 -0
  53. package/dist/commands/schedules.js.map +1 -0
  54. package/dist/commands/serve.d.ts +4 -0
  55. package/dist/commands/serve.d.ts.map +1 -0
  56. package/dist/commands/serve.js +633 -0
  57. package/dist/commands/serve.js.map +1 -0
  58. package/dist/commands/service.d.ts +9 -0
  59. package/dist/commands/service.d.ts.map +1 -0
  60. package/dist/commands/service.js +97 -0
  61. package/dist/commands/service.js.map +1 -0
  62. package/dist/commands/session.d.ts +9 -0
  63. package/dist/commands/session.d.ts.map +1 -0
  64. package/dist/commands/session.js +25 -0
  65. package/dist/commands/session.js.map +1 -0
  66. package/dist/commands/setup.d.ts +5 -0
  67. package/dist/commands/setup.d.ts.map +1 -0
  68. package/dist/commands/setup.js +2467 -0
  69. package/dist/commands/setup.js.map +1 -0
  70. package/dist/commands/skills.d.ts +15 -0
  71. package/dist/commands/skills.d.ts.map +1 -0
  72. package/dist/commands/skills.js +272 -0
  73. package/dist/commands/skills.js.map +1 -0
  74. package/dist/commands/template.d.ts +4 -0
  75. package/dist/commands/template.d.ts.map +1 -0
  76. package/dist/commands/template.js +593 -0
  77. package/dist/commands/template.js.map +1 -0
  78. package/dist/commands/update.d.ts +21 -0
  79. package/dist/commands/update.d.ts.map +1 -0
  80. package/dist/commands/update.js +291 -0
  81. package/dist/commands/update.js.map +1 -0
  82. package/dist/daemon.d.ts +74 -0
  83. package/dist/daemon.d.ts.map +1 -0
  84. package/dist/daemon.js +192 -0
  85. package/dist/daemon.js.map +1 -0
  86. package/dist/environment.d.ts +114 -0
  87. package/dist/environment.d.ts.map +1 -0
  88. package/dist/environment.js +2 -0
  89. package/dist/environment.js.map +1 -0
  90. package/dist/events.d.ts +17 -0
  91. package/dist/events.d.ts.map +1 -0
  92. package/dist/events.js +87 -0
  93. package/dist/events.js.map +1 -0
  94. package/dist/help.d.ts +2 -0
  95. package/dist/help.d.ts.map +1 -0
  96. package/dist/help.js +272 -0
  97. package/dist/help.js.map +1 -0
  98. package/dist/index.d.ts +32 -624
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +39 -6981
  101. package/dist/index.js.map +1 -1
  102. package/dist/io.d.ts +16 -0
  103. package/dist/io.d.ts.map +1 -0
  104. package/dist/io.js +45 -0
  105. package/dist/io.js.map +1 -0
  106. package/dist/loaders.d.ts +31 -0
  107. package/dist/loaders.d.ts.map +1 -0
  108. package/dist/loaders.js +56 -0
  109. package/dist/loaders.js.map +1 -0
  110. package/dist/main.d.ts +8 -0
  111. package/dist/main.d.ts.map +1 -0
  112. package/dist/main.js +218 -0
  113. package/dist/main.js.map +1 -0
  114. package/dist/npm.d.ts +66 -0
  115. package/dist/npm.d.ts.map +1 -0
  116. package/dist/npm.js +201 -0
  117. package/dist/npm.js.map +1 -0
  118. package/dist/parse.d.ts +245 -0
  119. package/dist/parse.d.ts.map +1 -0
  120. package/dist/parse.js +1098 -0
  121. package/dist/parse.js.map +1 -0
  122. package/dist/plugin-catalog.d.ts +44 -0
  123. package/dist/plugin-catalog.d.ts.map +1 -0
  124. package/dist/plugin-catalog.js +70 -0
  125. package/dist/plugin-catalog.js.map +1 -0
  126. package/dist/preflight.d.ts +60 -0
  127. package/dist/preflight.d.ts.map +1 -0
  128. package/dist/preflight.js +102 -0
  129. package/dist/preflight.js.map +1 -0
  130. package/dist/prompter.d.ts +84 -0
  131. package/dist/prompter.d.ts.map +1 -0
  132. package/dist/prompter.js +347 -0
  133. package/dist/prompter.js.map +1 -0
  134. package/dist/roster.d.ts +57 -0
  135. package/dist/roster.d.ts.map +1 -0
  136. package/dist/roster.js +78 -0
  137. package/dist/roster.js.map +1 -0
  138. package/dist/runtime.d.ts +76 -0
  139. package/dist/runtime.d.ts.map +1 -0
  140. package/dist/runtime.js +372 -0
  141. package/dist/runtime.js.map +1 -0
  142. package/dist/slack.d.ts +26 -0
  143. package/dist/slack.d.ts.map +1 -0
  144. package/dist/slack.js +113 -0
  145. package/dist/slack.js.map +1 -0
  146. package/dist/source.d.ts +24 -0
  147. package/dist/source.d.ts.map +1 -0
  148. package/dist/source.js +80 -0
  149. package/dist/source.js.map +1 -0
  150. package/dist/supervisor.d.ts +69 -0
  151. package/dist/supervisor.d.ts.map +1 -0
  152. package/dist/supervisor.js +218 -0
  153. package/dist/supervisor.js.map +1 -0
  154. package/dist/trusted-config.d.ts +84 -0
  155. package/dist/trusted-config.d.ts.map +1 -0
  156. package/dist/trusted-config.js +159 -0
  157. package/dist/trusted-config.js.map +1 -0
  158. 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"}