@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,376 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { agentsDirPath, defaultApiKeyEnvName, DEFAULT_STRATUS_AGENT, globalConfigPath, loadChannelCredentials, loadCredentials, loadRosterSouls, loadSoulFile, isSignedInRuntime, parseProviderName, readNonEmptyString, readProcessEnv, readWorkingDirectory, DEFAULT_CONFIG_FILENAME, loadConfigFile, resolveRuntimeConfig as resolveStateRuntimeConfig, CREDENTIAL_PROVIDER_NAMES, ignoredUntrustedConfigKeys, } from '@stratusagent/state';
4
+ import { readServiceCommand } from "../service.js";
5
+ import { serviceEnvFor } from "../daemon.js";
6
+ import { writeLine, pathExists } from "../io.js";
7
+ import { ignoredConfigRemedy } from "../runtime.js";
8
+ import { loadSlackAdapter } from "../loaders.js";
9
+ /**
10
+ * `stratus doctor` — what a run would resolve to right now, and which file
11
+ * or variable decided each part. Every "why is it using X" question needs
12
+ * the precedence chain, and reading it out of the source is not something
13
+ * anyone should have to do.
14
+ */
15
+ export const collectDoctorReport = async (command, warn, env = {}) => {
16
+ const processEnv = readProcessEnv(env);
17
+ const cwd = readWorkingDirectory(env);
18
+ const problems = [];
19
+ // Config discovery, spelled out rather than delegated: doctor has to
20
+ // report the files that LOST as well as the one in use, which is the
21
+ // whole point when a stray project config is the answer.
22
+ // Which of the two named it, not just that one did: telling someone to
23
+ // fix STRATUS_CONFIG when --config is what is set leaves the real
24
+ // override in place — the same mistake as provider and key attribution,
25
+ // in the one place a typo is most likely.
26
+ const explicitSource = command.configPath !== undefined
27
+ ? { name: '--config', value: command.configPath }
28
+ : readNonEmptyString(processEnv.STRATUS_CONFIG)
29
+ ? { name: 'STRATUS_CONFIG', value: String(processEnv.STRATUS_CONFIG) }
30
+ : undefined;
31
+ const explicit = explicitSource?.value;
32
+ const candidates = explicitSource
33
+ ? [{ path: path.resolve(cwd, explicitSource.value), label: explicitSource.name }]
34
+ : [
35
+ { path: path.join(cwd, DEFAULT_CONFIG_FILENAME), label: 'project' },
36
+ { path: globalConfigPath(env), label: 'global' },
37
+ ];
38
+ const present = [];
39
+ let unreadable;
40
+ for (const candidate of candidates) {
41
+ try {
42
+ await readFile(candidate.path, 'utf8');
43
+ present.push(candidate);
44
+ }
45
+ catch (error) {
46
+ const code = error.code;
47
+ if (code !== 'ENOENT') {
48
+ // resolveConfigLocation throws here rather than trying the next
49
+ // candidate, so discovery stops: a lower-priority file that a real
50
+ // run never reaches must not be reported as the config in use.
51
+ unreadable = candidate;
52
+ problems.push(`${candidate.path} exists but cannot be read (${error.message}). Every run fails here — discovery never reaches a lower-priority config.`);
53
+ break;
54
+ }
55
+ if (explicit) {
56
+ // Discovery treats a missing candidate as "try the next one", but
57
+ // an explicitly named config has no next one: a real run calls
58
+ // loadConfigFile on it and fails. Reporting built-in defaults here
59
+ // would describe a run that cannot happen, and hide the typo.
60
+ problems.push(`${candidate.path} does not exist, but ${candidate.label} names it — every run with this setting fails. `
61
+ + 'Fix the path, or drop the setting to fall back to config discovery.');
62
+ }
63
+ }
64
+ }
65
+ const winner = unreadable ?? present[0];
66
+ const shadowed = unreadable ? [] : present.slice(1);
67
+ if (winner && shadowed.length > 0 && winner.label.startsWith('project')) {
68
+ problems.push(`${winner.path} outranks ${shadowed.map((entry) => entry.path).join(' and ')} for runs started in this directory. `
69
+ + 'Run from elsewhere, or pass --config to pick one explicitly.');
70
+ }
71
+ let fileConfig = {};
72
+ let configFatal = unreadable !== undefined;
73
+ if (winner && !unreadable) {
74
+ try {
75
+ fileConfig = await loadConfigFile(winner.path);
76
+ }
77
+ catch (error) {
78
+ // resolveRuntimeConfig propagates this — no run reaches provider or
79
+ // credential resolution, so presenting defaults as resolved settings
80
+ // would describe a run that cannot happen.
81
+ configFatal = true;
82
+ problems.push(`${winner.path} could not be parsed (${error.message}). Every run fails until it is fixed or removed.`);
83
+ warn(`ignoring unreadable config ${winner.path}`);
84
+ }
85
+ }
86
+ // Which variable supplied a value, not just the value: naming the wrong
87
+ // one sends the reader to unset something that was never the cause,
88
+ // leaving the real override in place.
89
+ const envPick = (name) => {
90
+ const value = readNonEmptyString(processEnv[name]);
91
+ return typeof value === 'string' ? { name, value } : undefined;
92
+ };
93
+ /**
94
+ * The verdict comes from the resolver, not from a second copy of its
95
+ * rules. Everything below only *attributes* values to the file or
96
+ * variable that supplied them — which the resolver does not report —
97
+ * while whether a run works at all, and what it bills, is whatever
98
+ * resolveRuntimeConfig actually returns or throws.
99
+ */
100
+ const envSoul = envPick('STRATUS_SOUL');
101
+ // The file's soul under the resolver's trust rule: a project-local file
102
+ // does not name one, so doctor must not attribute one to it.
103
+ const soulValue = envSoul?.value ?? (winner?.label === 'project' ? undefined : fileConfig.soul);
104
+ const soulSource = envSoul ? envSoul.name : (winner ? winner.path : '');
105
+ const soulPath = typeof soulValue === 'string' ? path.resolve(cwd, soulValue) : undefined;
106
+ // Loaded here for ATTRIBUTION only — the soul's frontmatter is what
107
+ // explains a provider nobody wrote in a config file. Whether a run works
108
+ // is still the resolver's verdict below.
109
+ const soul = soulPath ? await loadSoulFile(soulPath).catch(() => undefined) : undefined;
110
+ let resolved;
111
+ if (!configFatal) {
112
+ try {
113
+ resolved = await resolveStateRuntimeConfig(command.configPath ? { configPath: command.configPath } : {}, env);
114
+ }
115
+ catch (error) {
116
+ const message = error instanceof Error ? error.message : String(error);
117
+ problems.push(`No run can start: ${message}`);
118
+ if (soulPath && /soul/i.test(message)) {
119
+ // Worth saying explicitly: a soul that fails to load is fatal, not
120
+ // a quiet downgrade to the built-in agent.
121
+ problems.push(`Every run fails until ${soulPath} is fixed or the soul setting is removed — the built-in agent is not substituted.`);
122
+ }
123
+ }
124
+ }
125
+ // A refused persona is a finding, not a silence: the file asks for a soul
126
+ // or a preamble, no run started here will use it, and a doctor that said
127
+ // "no soul configured" would be hiding the trust decision it exists to
128
+ // explain. The resolver's own record is the verdict — it already leaves
129
+ // out a key the environment outranked, which is not refused but beaten —
130
+ // and only when no run could resolve at all is the same rule applied
131
+ // here, so the finding still appears beside the failure that hid it.
132
+ const refusedByTrust = resolved?.ignoredFromUntrustedConfig
133
+ ?? ignoredUntrustedConfigKeys({}, fileConfig, winner ? { path: winner.path, trusted: winner.label !== 'project' } : undefined, env);
134
+ if (refusedByTrust) {
135
+ problems.push(`${refusedByTrust.path} sets ${refusedByTrust.keys.join(' and ')}, which an auto-discovered config does not get to choose — `
136
+ + `every run started here ignores ${refusedByTrust.keys.length === 1 ? 'it' : 'them'}. `
137
+ + ignoredConfigRemedy(refusedByTrust, false));
138
+ }
139
+ const envProviderPick = envPick('STRATUS_PROVIDER');
140
+ const providerSource = envProviderPick
141
+ ? envProviderPick.name
142
+ : soul?.provider
143
+ ? `${soulPath} (soul frontmatter)`
144
+ : fileConfig.provider
145
+ ? (winner?.path ?? 'config')
146
+ : 'built-in default — nothing set a provider';
147
+ // When resolution fails the intended provider is still worth reporting:
148
+ // "why is it anthropic" is exactly the question, and the problems below
149
+ // already say no run can start.
150
+ const intendedProvider = envProviderPick?.value ?? soul?.provider ?? fileConfig.provider ?? 'demo';
151
+ const provider = resolved
152
+ ? { value: resolved.provider, source: providerSource }
153
+ : { value: `${intendedProvider} (unreachable)`, source: providerSource };
154
+ if (provider.value === 'demo') {
155
+ // Setup writes the config file, which is the LOWEST precedence of the
156
+ // three — so when an env var or a soul chose demo, "run setup" is
157
+ // advice that changes nothing and leaves every run on demo.
158
+ const fix = envProviderPick
159
+ ? `Unset ${envProviderPick.name}; it outranks both your config and any soul.`
160
+ : soul?.provider === 'demo'
161
+ ? `Change or remove the provider pin in ${soulPath}; a soul outranks the config file.`
162
+ : fileConfig.provider === 'demo'
163
+ ? `Change "provider" in ${winner?.path}, or run \`stratus setup\` → Providers.`
164
+ : 'Run `stratus setup` → Providers and sign in, then Save & finish.';
165
+ problems.push(`Provider is the offline demo model, so replies are canned. ${fix}`);
166
+ }
167
+ let model;
168
+ if (resolved && resolved.provider !== 'demo') {
169
+ const envModel = envPick('STRATUS_MODEL');
170
+ // A soul's model belongs to the soul's provider, and the config's model
171
+ // to the config's provider — either can be stranded by an override.
172
+ // The soul's pin in resolved form, so a soul saying `ollama` matches
173
+ // the `plugin:ollama` the run resolved to.
174
+ const soulModelApplies = soul?.provider === undefined || parseProviderName(soul.provider, 'soul file') === resolved.provider;
175
+ const configModelApplies = (fileConfig.provider ?? 'openai') === resolved.provider;
176
+ model = {
177
+ value: resolved.model ?? 'the provider\'s own default',
178
+ source: envModel
179
+ ? envModel.name
180
+ : soulModelApplies && soul?.model === resolved.model
181
+ ? `${soulPath} (soul frontmatter)`
182
+ : configModelApplies && fileConfig.model === resolved.model
183
+ ? (winner?.path ?? 'config')
184
+ : 'built-in default for this provider',
185
+ };
186
+ }
187
+ const credentials = await loadCredentials(env);
188
+ const signIns = [];
189
+ const usedKeyEnvVar = resolved && isSignedInRuntime(resolved) ? resolved.apiKeyEnvVar : undefined;
190
+ const usesAuthToken = resolved?.provider === 'anthropic' && resolved.authToken !== undefined;
191
+ const fallback = resolved && resolved.provider !== 'demo' ? resolved.fallback : undefined;
192
+ for (const target of CREDENTIAL_PROVIDER_NAMES) {
193
+ const stored = credentials[target];
194
+ const label = stored?.type === 'oauth_token'
195
+ ? (target === 'codex' ? 'ChatGPT sign-in (codex login)' : 'Claude subscription (Pro/Max)')
196
+ : 'API key';
197
+ const isDefault = resolved?.provider === target;
198
+ const isFallback = fallback?.provider === target;
199
+ // A provider no resolved run consults is reported, never diagnosed:
200
+ // flagging an override on a credential nothing reads is a false alarm.
201
+ if (!isDefault && !isFallback) {
202
+ signIns.push({
203
+ provider: target,
204
+ status: stored
205
+ ? `${label} (unused — ${resolved ? resolved.provider : 'nothing'} serves your runs)`
206
+ : 'not signed in',
207
+ });
208
+ continue;
209
+ }
210
+ const envVar = isDefault ? usedKeyEnvVar : defaultApiKeyEnvName(target);
211
+ const viaEnv = isDefault
212
+ ? usedKeyEnvVar !== undefined
213
+ : fallback?.apiKey !== undefined && fallback.apiKey === readNonEmptyString(processEnv[String(envVar)]);
214
+ const where = isDefault ? 'runs are' : 'fallback runs are';
215
+ if (stored && viaEnv) {
216
+ signIns.push({ provider: target, status: `${label}, overridden by ${envVar} in your environment` });
217
+ // The costly case: an env key silently demotes a subscription to
218
+ // per-token billing, and nothing in a normal run says so.
219
+ problems.push(stored.type === 'oauth_token'
220
+ ? `${envVar} in your environment outranks your saved ${target} subscription sign-in, so ${where} billed per token instead of through your plan. Unset it (check your shell profile) to use the subscription.`
221
+ : `${envVar} in your environment outranks your saved ${target} sign-in. Unset it to use the one \`stratus setup\` stored.`);
222
+ continue;
223
+ }
224
+ if (viaEnv) {
225
+ signIns.push({ provider: target, status: `using ${envVar} from your environment` });
226
+ continue;
227
+ }
228
+ if (stored) {
229
+ signIns.push({ provider: target, status: isDefault && usesAuthToken ? `${label} — runs go through the Claude Code runtime` : label });
230
+ continue;
231
+ }
232
+ signIns.push({ provider: target, status: 'not signed in' });
233
+ }
234
+ // A fallback the resolver dropped is the quiet failure: the config still
235
+ // names one, but a failing primary has nothing to retry on.
236
+ if (fileConfig.fallbackModel !== undefined && resolved && resolved.provider !== 'demo' && !fallback) {
237
+ problems.push(`A fallback model (${fileConfig.fallbackModel}) is configured but could not be resolved — usually no sign-in for its provider, or an endpoint its saved key is not sent to. `
238
+ + 'A failing primary model has nothing to retry on.');
239
+ }
240
+ const channels = await loadChannelCredentials(env);
241
+ const slackAgents = Object.keys(channels.slack ?? {}).sort();
242
+ const slackPackageInstalled = (await loadSlackAdapter()) !== undefined;
243
+ if (slackAgents.length > 0 && !slackPackageInstalled) {
244
+ problems.push(`Slack tokens are stored for ${slackAgents.length} agent(s) but @stratusagent/channel-slack is not installed, so \`stratus serve\` skips them. `
245
+ + 'Install it with: npm install -g @stratusagent/channel-slack');
246
+ }
247
+ let rosterCount = 0;
248
+ try {
249
+ rosterCount = (await readdir(agentsDirPath(env))).filter((file) => file.endsWith('.md')).length;
250
+ }
251
+ catch (error) {
252
+ if (error.code !== 'ENOENT') {
253
+ throw error;
254
+ }
255
+ }
256
+ // Tokens keyed to an agent the roster no longer has are loaded and
257
+ // skipped on every start, silently.
258
+ let rosterEntries = [];
259
+ let rosterLoaded = true;
260
+ try {
261
+ rosterEntries = await loadRosterSouls(env, warn);
262
+ }
263
+ catch (error) {
264
+ // Doctor exists to name problems, so a roster it cannot load is a
265
+ // finding to report — not an exception that replaces the report.
266
+ rosterLoaded = false;
267
+ problems.push(error instanceof Error ? error.message : String(error));
268
+ }
269
+ const rosterIds = new Set(rosterEntries.map((entry) => entry.soul.agent.id));
270
+ rosterIds.add(DEFAULT_STRATUS_AGENT.id);
271
+ if (soul) {
272
+ rosterIds.add(soul.agent.id);
273
+ }
274
+ // Only against a roster that actually loaded. "No agent has this id" is
275
+ // a claim about the roster, and a refused one cannot support it — every
276
+ // stored token would be reported as orphaned, and this advises clearing
277
+ // them. Advice is not deletion, but an operator who follows it loses the
278
+ // same credentials by hand.
279
+ const orphans = rosterLoaded ? slackAgents.filter((id) => !rosterIds.has(id)) : [];
280
+ if (orphans.length > 0) {
281
+ problems.push(`Slack tokens are stored for ${orphans.join(', ')}, which no agent matches — \`stratus serve\` skips them. `
282
+ + 'Clear them from `stratus setup` → Channels.');
283
+ }
284
+ // The invisible failure doctor exists to surface: the service unit embeds
285
+ // absolute node and entrypoint paths, and upgrading node (an nvm version
286
+ // directory, say) leaves the unit pointing at an interpreter that no
287
+ // longer exists. The service stops working and nothing else says so.
288
+ const unitCommand = await readServiceCommand(serviceEnvFor(env));
289
+ if (unitCommand?.execPath !== undefined && !(await pathExists(unitCommand.execPath))) {
290
+ problems.push(`The service unit points at a node interpreter that no longer exists (${unitCommand.execPath}), so stratusd cannot start. `
291
+ + 'Run `stratus update` (or `stratus service install`) to rewrite it with current paths.');
292
+ }
293
+ if (unitCommand?.scriptPath !== undefined && !(await pathExists(unitCommand.scriptPath))) {
294
+ problems.push(`The service unit points at a CLI entrypoint that no longer exists (${unitCommand.scriptPath}), so stratusd cannot start. `
295
+ + 'Run `stratus update` (or `stratus service install`) to rewrite it with current paths.');
296
+ }
297
+ return {
298
+ ...(winner ? { configInUse: winner.path } : {}),
299
+ configShadowed: shadowed.map((entry) => entry.path),
300
+ provider,
301
+ ...(model ? { model } : {}),
302
+ ...(soulPath ? { soul: { value: soulPath, source: soulSource } } : {}),
303
+ ...(soul ? { agent: `${soul.agent.name} (${soul.agent.id})` } : {}),
304
+ ...(fallback ? { fallback: { provider: fallback.provider, model: fallback.model } } : {}),
305
+ signIns,
306
+ slackAgents,
307
+ slackPackageInstalled,
308
+ rosterCount,
309
+ problems,
310
+ };
311
+ };
312
+ export const runDoctor = async (command, streams, env = {}) => {
313
+ const report = await collectDoctorReport(command, (message) => {
314
+ writeLine(streams.stderr, `Warning: ${message}.`);
315
+ }, env);
316
+ if (command.format === 'json') {
317
+ writeLine(streams.stdout, JSON.stringify(report, null, 2));
318
+ return report.problems.length > 0 ? 1 : 0;
319
+ }
320
+ const field = (label, setting) => {
321
+ if (!setting) {
322
+ return;
323
+ }
324
+ writeLine(streams.stdout, ` ${label.padEnd(10)}${setting.value}`);
325
+ writeLine(streams.stdout, ` ${''.padEnd(10)}from ${setting.source}`);
326
+ };
327
+ writeLine(streams.stdout, 'Stratus Agent — what a run would use right now');
328
+ writeLine(streams.stdout);
329
+ field('provider', report.provider);
330
+ field('model', report.model);
331
+ field('soul', report.soul);
332
+ if (report.agent) {
333
+ writeLine(streams.stdout, ` ${'agent'.padEnd(10)}${report.agent}`);
334
+ }
335
+ else if (report.soul) {
336
+ // A soul is configured but did not load — saying "built-in" here would
337
+ // describe a run that cannot happen.
338
+ writeLine(streams.stdout, ` ${'agent'.padEnd(10)}unresolved — the configured soul could not be read`);
339
+ }
340
+ else {
341
+ writeLine(streams.stdout, ` ${'agent'.padEnd(10)}${DEFAULT_STRATUS_AGENT.name} (built-in — no soul configured)`);
342
+ }
343
+ writeLine(streams.stdout);
344
+ writeLine(streams.stdout, 'Files');
345
+ writeLine(streams.stdout, ` config ${report.configInUse ?? 'none found — built-in defaults apply'}`);
346
+ for (const shadowedPath of report.configShadowed) {
347
+ writeLine(streams.stdout, ` (${shadowedPath} exists but is outranked)`);
348
+ }
349
+ writeLine(streams.stdout, ` agents ${report.rosterCount} soul file${report.rosterCount === 1 ? '' : 's'}`);
350
+ if (report.fallback) {
351
+ writeLine(streams.stdout, ` ${'fallback'.padEnd(10)}${report.fallback.provider} · ${report.fallback.model}`);
352
+ writeLine(streams.stdout, ` ${''.padEnd(10)}used when the default model errors mid-run`);
353
+ }
354
+ writeLine(streams.stdout);
355
+ writeLine(streams.stdout, 'Sign-ins');
356
+ for (const entry of report.signIns) {
357
+ writeLine(streams.stdout, ` ${entry.provider.padEnd(10)}${entry.status}`);
358
+ }
359
+ writeLine(streams.stdout);
360
+ writeLine(streams.stdout, 'Channels');
361
+ writeLine(streams.stdout, ` slack ${report.slackAgents.length === 0
362
+ ? 'no agents connected'
363
+ : `${report.slackAgents.length} connected (${report.slackAgents.join(', ')})`}`);
364
+ writeLine(streams.stdout, ` @stratusagent/channel-slack ${report.slackPackageInstalled ? 'installed' : 'not installed'}`);
365
+ writeLine(streams.stdout);
366
+ if (report.problems.length === 0) {
367
+ writeLine(streams.stdout, 'No problems found.');
368
+ return 0;
369
+ }
370
+ writeLine(streams.stdout, `${report.problems.length} problem${report.problems.length === 1 ? '' : 's'} found:`);
371
+ for (const problem of report.problems) {
372
+ writeLine(streams.stdout, ` ! ${problem}`);
373
+ }
374
+ return 1;
375
+ };
376
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { CliStreams, CliEnvironment } from '../environment.ts';
2
+ import type { ParsedGrantsCommand } from '../parse.ts';
3
+ /**
4
+ * `stratus grants <agent>` and `stratus grants revoke <agent> …` — the
5
+ * operator's view of what an agent may do unattended, and the way to take
6
+ * one back.
7
+ *
8
+ * Through the running daemon when one says it is serving, and only then
9
+ * from the files, because of the daemon's cache: the store reads each
10
+ * agent's file once per process, so a revoke that edited the file behind a
11
+ * live daemon would leave the policy honouring a grant the listing no
12
+ * longer shows until the next restart. Going through `POST
13
+ * /agents/:id/grants/revoke` is what makes a revoke the next call's answer.
14
+ * A daemon that `gateway.json` names but that does not answer falls back
15
+ * to the files with a warning saying exactly that, since the file is still
16
+ * the truth for the next daemon to start.
17
+ */
18
+ export declare const runGrants: (command: ParsedGrantsCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
19
+ //# sourceMappingURL=grants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../../src/commands/grants.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAQvD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,SAAS,GACpB,SAAS,mBAAmB,EAC5B,SAAS,UAAU,EACnB,MAAK,cAAmB,KACvB,OAAO,CAAC,MAAM,CAmHhB,CAAC"}
@@ -0,0 +1,128 @@
1
+ import { createFileCommandWhitelist, describeAgentGrants, describeToolGrant, whitelistPathFor, } from '@stratusagent/permissions';
2
+ import { agentsDirPath, gatewayInfoPath } from '@stratusagent/state';
3
+ import { callRunningGateway, gatewayErrorMessage, readGatewayInfo } from "../daemon.js";
4
+ import { writeLine } from "../io.js";
5
+ /**
6
+ * `stratus grants <agent>` and `stratus grants revoke <agent> …` — the
7
+ * operator's view of what an agent may do unattended, and the way to take
8
+ * one back.
9
+ *
10
+ * Through the running daemon when one says it is serving, and only then
11
+ * from the files, because of the daemon's cache: the store reads each
12
+ * agent's file once per process, so a revoke that edited the file behind a
13
+ * live daemon would leave the policy honouring a grant the listing no
14
+ * longer shows until the next restart. Going through `POST
15
+ * /agents/:id/grants/revoke` is what makes a revoke the next call's answer.
16
+ * A daemon that `gateway.json` names but that does not answer falls back
17
+ * to the files with a warning saying exactly that, since the file is still
18
+ * the truth for the next daemon to start.
19
+ */
20
+ export const runGrants = async (command, streams, env = {}) => {
21
+ const agentId = command.agentId;
22
+ const encoded = encodeURIComponent(agentId);
23
+ const base = command.gateway
24
+ ? command.gateway.replace(/\/+$/, '')
25
+ : (await readGatewayInfo(env))?.url.replace(/\/+$/, '');
26
+ const revocation = command.action === 'revoke'
27
+ ? command.tool !== undefined
28
+ ? { tool: command.tool }
29
+ : command.scope !== undefined
30
+ ? { scope: command.scope }
31
+ : { origin: command.origin ?? '' }
32
+ : undefined;
33
+ const named = revocation?.tool ?? revocation?.scope ?? revocation?.origin ?? '';
34
+ const fromFiles = async () => {
35
+ const store = createFileCommandWhitelist({
36
+ directory: agentsDirPath(env),
37
+ warn: (line) => writeLine(streams.stderr, `Warning: ${line}`),
38
+ });
39
+ if (revocation) {
40
+ const revoked = revocation.tool !== undefined
41
+ ? await store.forgetTool(agentId, revocation.tool)
42
+ : revocation.scope !== undefined
43
+ ? await store.forgetScope(agentId, revocation.scope)
44
+ : await store.forgetOrigin(agentId, revocation.origin ?? '');
45
+ return reportRevocation(revoked);
46
+ }
47
+ const listing = { agentId, ...describeAgentGrants(await store.grantsFor(agentId)) };
48
+ return render(listing, `${whitelistPathFor(agentsDirPath(env), agentId)}`);
49
+ };
50
+ const reportRevocation = (revoked) => {
51
+ if (!revoked) {
52
+ writeLine(streams.stderr, `${agentId} has no such grant. \`stratus grants ${agentId}\` lists what exists.`);
53
+ return 1;
54
+ }
55
+ writeLine(streams.stdout, `Revoked ${named} for ${agentId}.`);
56
+ return 0;
57
+ };
58
+ const render = (listing, source) => {
59
+ if (command.format === 'json') {
60
+ writeLine(streams.stdout, JSON.stringify({ ...listing, source }, null, 2));
61
+ return 0;
62
+ }
63
+ const total = listing.tools.length + listing.scopes.length + listing.origins.length;
64
+ if (total === 0) {
65
+ writeLine(streams.stdout, `${agentId} has no standing grants beyond the built-in safe list (${source}).`);
66
+ writeLine(streams.stdout, 'An "always allow" answered on one of its gated calls creates one.');
67
+ return 0;
68
+ }
69
+ writeLine(streams.stdout, `${agentId} may do this unattended, beyond the built-in safe list (${source}):`);
70
+ if (listing.tools.length > 0) {
71
+ writeLine(streams.stdout, ' tools');
72
+ for (const grant of listing.tools) {
73
+ const by = grant.grantedBy ? ` by ${grant.grantedBy}` : '';
74
+ const stale = grant.stale ? ` — stale: ${grant.stale}` : '';
75
+ writeLine(streams.stdout, ` ${describeToolGrant(grant)} (granted ${grant.grantedAt}${by})${stale}`);
76
+ }
77
+ }
78
+ if (listing.scopes.length > 0) {
79
+ writeLine(streams.stdout, ' commands');
80
+ for (const row of listing.scopes) {
81
+ writeLine(streams.stdout, ` ${row.description}`);
82
+ }
83
+ }
84
+ if (listing.origins.length > 0) {
85
+ writeLine(streams.stdout, ' sites');
86
+ for (const row of listing.origins) {
87
+ writeLine(streams.stdout, ` ${row.origin}`);
88
+ }
89
+ }
90
+ writeLine(streams.stdout, `Take one back: stratus grants revoke ${agentId} --tool <name> | --scope "<command>" | --origin <origin>`);
91
+ return 0;
92
+ };
93
+ if (!base) {
94
+ return fromFiles();
95
+ }
96
+ let response;
97
+ try {
98
+ response = revocation
99
+ ? await callRunningGateway(env, command, base, `/api/v1/agents/${encoded}/grants/revoke`, revocation)
100
+ : await callRunningGateway(env, command, base, `/api/v1/agents/${encoded}/grants`, undefined, 'GET');
101
+ }
102
+ catch (error) {
103
+ if (command.gateway) {
104
+ throw error;
105
+ }
106
+ // Named by the file, not answering: a daemon that crashed leaves the
107
+ // file behind. The files are still the truth for the next one to
108
+ // start, so act on them — and say so, because if a daemon *is* alive
109
+ // behind a broken API it keeps its cached view until it restarts.
110
+ writeLine(streams.stderr, `Warning: ${gatewayInfoPath(env)} names a daemon at ${base}, but it did not answer `
111
+ + `(${error instanceof Error ? error.message : String(error)}). `
112
+ + `${revocation ? 'Revoking in' : 'Reading'} ${whitelistPathFor(agentsDirPath(env), agentId)} instead; `
113
+ + 'a daemon that is running will not notice until it restarts.');
114
+ return fromFiles();
115
+ }
116
+ if (response.status === 404 && revocation) {
117
+ return reportRevocation(false);
118
+ }
119
+ if (!response.ok) {
120
+ writeLine(streams.stderr, `Error: ${await gatewayErrorMessage(response)}`);
121
+ return 1;
122
+ }
123
+ if (revocation) {
124
+ return reportRevocation(true);
125
+ }
126
+ return render(await response.json(), `from the daemon at ${base}`);
127
+ };
128
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../../src/commands/grants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { CliStreams, CliEnvironment } from '../environment.ts';
2
+ import type { ParsedLogsCommand } from '../parse.ts';
3
+ /**
4
+ * `stratus logs` — the daemon's structured log, filtered. `serve` streams
5
+ * to its own stdout, which is gone the moment it runs under a service
6
+ * manager; this reads the file it also writes, from any terminal.
7
+ */
8
+ export declare const runLogs: (command: ParsedLogsCommand, streams: CliStreams, env?: CliEnvironment) => Promise<number>;
9
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAClB,SAAS,iBAAiB,EAC1B,SAAS,UAAU,EACnB,MAAK,cAAmB,KACvB,OAAO,CAAC,MAAM,CAkDhB,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { logsDirPath } from '@stratusagent/state';
2
+ import { currentLogPosition, formatLogRecord, readRecentRecords, tailLog, } from "../logs.js";
3
+ import { writeLine } from "../io.js";
4
+ /**
5
+ * `stratus logs` — the daemon's structured log, filtered. `serve` streams
6
+ * to its own stdout, which is gone the moment it runs under a service
7
+ * manager; this reads the file it also writes, from any terminal.
8
+ */
9
+ export const runLogs = async (command, streams, env = {}) => {
10
+ const dir = logsDirPath(env);
11
+ const filter = {
12
+ ...(command.agentId ? { agentId: command.agentId } : {}),
13
+ ...(command.sessionId ? { sessionId: command.sessionId } : {}),
14
+ };
15
+ const emit = (record) => {
16
+ writeLine(streams.stdout, command.format === 'json' ? JSON.stringify(record) : formatLogRecord(record));
17
+ };
18
+ // Captured BEFORE the backlog is read: the daemon keeps writing while a
19
+ // large backlog prints, and a follower that takes its offset afterwards
20
+ // skips everything written in between — permanently.
21
+ const followFrom = command.follow ? await currentLogPosition(dir) : undefined;
22
+ // Bounded by the same offset the follower resumes from: without it, a
23
+ // record written between the two reads is printed by the backlog and
24
+ // then again by the stream.
25
+ const recent = await readRecentRecords(dir, command.limit, filter, followFrom);
26
+ for (const record of recent) {
27
+ emit(record);
28
+ }
29
+ if (!command.follow) {
30
+ if (recent.length === 0 && command.format === 'text') {
31
+ writeLine(streams.stdout, `No log records yet in ${dir}. Start the daemon with \`stratus serve\`.`);
32
+ }
33
+ return 0;
34
+ }
35
+ const controller = new AbortController();
36
+ const stop = () => controller.abort();
37
+ process.once('SIGINT', stop);
38
+ process.once('SIGTERM', stop);
39
+ env.shutdownSignal?.addEventListener('abort', stop, { once: true });
40
+ if (env.shutdownSignal?.aborted) {
41
+ stop();
42
+ }
43
+ try {
44
+ await tailLog({
45
+ dir,
46
+ filter,
47
+ ...(followFrom !== undefined ? { startPosition: followFrom } : {}),
48
+ signal: controller.signal,
49
+ onRecord: emit,
50
+ });
51
+ }
52
+ finally {
53
+ process.off('SIGINT', stop);
54
+ process.off('SIGTERM', stop);
55
+ }
56
+ return 0;
57
+ };
58
+ //# sourceMappingURL=logs.js.map