@stratusagent/cli 0.11.3 → 0.11.5
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 +15 -3
- package/dist/approvals.d.ts +7 -1
- package/dist/approvals.d.ts.map +1 -1
- package/dist/approvals.js +59 -6
- package/dist/approvals.js.map +1 -1
- package/dist/commands/agent-new.d.ts.map +1 -1
- package/dist/commands/agent-new.js +12 -7
- package/dist/commands/agent-new.js.map +1 -1
- package/dist/commands/chat.d.ts +1 -1
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +7 -4
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +32 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/grants.d.ts.map +1 -1
- package/dist/commands/grants.js +8 -3
- package/dist/commands/grants.js.map +1 -1
- package/dist/commands/memory.d.ts +16 -3
- package/dist/commands/memory.d.ts.map +1 -1
- package/dist/commands/memory.js +322 -16
- package/dist/commands/memory.js.map +1 -1
- package/dist/commands/plugins.d.ts +12 -0
- package/dist/commands/plugins.d.ts.map +1 -1
- package/dist/commands/plugins.js +30 -7
- package/dist/commands/plugins.js.map +1 -1
- package/dist/commands/schedules.d.ts.map +1 -1
- package/dist/commands/schedules.js +136 -31
- package/dist/commands/schedules.js.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +51 -3
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +87 -17
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/template.d.ts.map +1 -1
- package/dist/commands/template.js +28 -7
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/update.d.ts +0 -17
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +63 -31
- package/dist/commands/update.js.map +1 -1
- package/dist/companions.d.ts +34 -0
- package/dist/companions.d.ts.map +1 -0
- package/dist/companions.js +45 -0
- package/dist/companions.js.map +1 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +3 -0
- package/dist/daemon.js.map +1 -1
- package/dist/environment.d.ts +6 -0
- package/dist/environment.d.ts.map +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +27 -9
- package/dist/events.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.d.ts.map +1 -1
- package/dist/help.js +41 -7
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +20 -5
- package/dist/main.js.map +1 -1
- package/dist/npm.d.ts +1 -1
- package/dist/npm.js +1 -1
- package/dist/parse.d.ts +42 -5
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +90 -17
- package/dist/parse.js.map +1 -1
- package/dist/plugin-catalog.d.ts +9 -0
- package/dist/plugin-catalog.d.ts.map +1 -1
- package/dist/plugin-catalog.js +12 -0
- package/dist/plugin-catalog.js.map +1 -1
- package/dist/runtime.d.ts +28 -11
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +178 -71
- package/dist/runtime.js.map +1 -1
- package/dist/service.d.ts +23 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +41 -2
- package/dist/service.js.map +1 -1
- package/dist/trusted-config.d.ts +43 -1
- package/dist/trusted-config.d.ts.map +1 -1
- package/dist/trusted-config.js +99 -5
- package/dist/trusted-config.js.map +1 -1
- package/package.json +25 -23
package/dist/commands/setup.js
CHANGED
|
@@ -4,7 +4,7 @@ import { preflightPlugin, readPluginManifest, PluginConfigError, PluginManifestE
|
|
|
4
4
|
import { DEFAULT_ANTHROPIC_MODEL } from '@stratusagent/provider-anthropic';
|
|
5
5
|
import { DEFAULT_CODEX_MODEL } from '@stratusagent/provider-codex';
|
|
6
6
|
import { formatSoul, parseSoul } from '@stratusagent/agents';
|
|
7
|
-
import { claimSoulFile, collectAvailableModels as collectModels, credentialsPath, defaultApiKeyEnvName, DEFAULT_ANTHROPIC_BASE_URL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_STRATUS_AGENT, globalConfigPath, loadChannelCredentials, loadCredentials, loadRosterSouls, loadSoulFile, readNonEmptyString, readProcessEnv, readWorkingDirectory, resolveAgentApprovals, DEFAULT_CONFIG_FILENAME, loadConfigFile, saveChannelCredentials, saveConfigFile, saveCredentials, CREDENTIAL_PROVIDER_NAMES, verifyProviderKey,
|
|
7
|
+
import { claimSoulFile, collectAvailableModels as collectModels, credentialsPath, defaultApiKeyEnvName, DEFAULT_ANTHROPIC_BASE_URL, DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_MODEL, DEFAULT_STRATUS_AGENT, globalConfigPath, loadChannelCredentials, loadCredentials, loadRosterSouls, loadSoulFile, isRegisteredProviderName, readNonEmptyString, registeredProviderNameOf, readProcessEnv, readWorkingDirectory, resolveAgentApprovals, DEFAULT_CONFIG_FILENAME, loadConfigFile, saveChannelCredentials, saveConfigFile, saveCredentials, CREDENTIAL_PROVIDER_NAMES, verifyProviderKey, } from '@stratusagent/state';
|
|
8
8
|
import { installService, readServiceStatus, servicePlatform, serviceUnitPath, uninstallService, } from "../service.js";
|
|
9
9
|
import { classifyApprovalReach, unattendedReachParts } from "../approvals.js";
|
|
10
10
|
import { serviceEnvFor } from "../daemon.js";
|
|
@@ -101,6 +101,17 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
101
101
|
...(existing.approvals !== undefined ? { approvals: existing.approvals } : {}),
|
|
102
102
|
...(existing.api !== undefined ? { api: existing.api } : {}),
|
|
103
103
|
...(existing.principals !== undefined ? { principals: existing.principals } : {}),
|
|
104
|
+
...(existing.slack !== undefined ? { slack: existing.slack } : {}),
|
|
105
|
+
// Settings setup has no menu for, carried through a save untouched: a
|
|
106
|
+
// re-run that dropped them would put the operator's agents back on the
|
|
107
|
+
// host and the file store without a word — and, for the two bounds,
|
|
108
|
+
// back on defaults their model cannot serve. A `maxTokens` set because
|
|
109
|
+
// a proxy's ceiling is under 16000 would silently return to 16000 and
|
|
110
|
+
// fail every request; a raised `maxTurns` would return to 8.
|
|
111
|
+
...(existing.executor !== undefined ? { executor: existing.executor } : {}),
|
|
112
|
+
...(existing.memoryStore !== undefined ? { memoryStore: existing.memoryStore } : {}),
|
|
113
|
+
...(existing.maxTokens !== undefined ? { maxTokens: existing.maxTokens } : {}),
|
|
114
|
+
...(existing.maxTurns !== undefined ? { maxTurns: existing.maxTurns } : {}),
|
|
104
115
|
credentials: await loadCredentials(env),
|
|
105
116
|
credentialsDirty: false,
|
|
106
117
|
channels: await loadChannelCredentials(env),
|
|
@@ -126,14 +137,24 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
126
137
|
header: stratusHeaderLines,
|
|
127
138
|
consumeNotices: () => recentNotices.splice(0),
|
|
128
139
|
});
|
|
129
|
-
const
|
|
140
|
+
const builtInDefaultModel = (provider) => provider === 'openai'
|
|
130
141
|
? DEFAULT_OPENAI_MODEL
|
|
131
142
|
: provider === 'codex'
|
|
132
143
|
? DEFAULT_CODEX_MODEL
|
|
133
144
|
: DEFAULT_ANTHROPIC_MODEL;
|
|
145
|
+
// A contributed provider's default is its own, so setup has none to
|
|
146
|
+
// name for it — and none to write into a config or a soul.
|
|
147
|
+
const defaultModelFor = (provider) => isRegisteredProviderName(provider) ? undefined : builtInDefaultModel(provider);
|
|
134
148
|
// Widened to CliProviderName only so setup can ask about the provider it
|
|
135
149
|
// currently has selected, `demo` included; the rule itself is the shared one.
|
|
136
|
-
const defaultKeyEnvFor = (provider) => defaultApiKeyEnvName(provider
|
|
150
|
+
const defaultKeyEnvFor = (provider) => defaultApiKeyEnvName(credentialProviderOf(provider) ?? 'anthropic');
|
|
151
|
+
/**
|
|
152
|
+
* The sign-in a selection is stored under, or nothing: the demo provider
|
|
153
|
+
* has none, and a provider a plugin registered brings its own through
|
|
154
|
+
* its plugin's config and credentials — setup neither stores nor checks
|
|
155
|
+
* one for it.
|
|
156
|
+
*/
|
|
157
|
+
const credentialProviderOf = (provider) => provider === 'demo' || isRegisteredProviderName(provider) ? undefined : provider;
|
|
137
158
|
const credentialLabel = (provider, credential) => credential.type === 'oauth_token'
|
|
138
159
|
? (provider === 'codex' ? 'ChatGPT sign-in' : 'Claude subscription')
|
|
139
160
|
: 'API key';
|
|
@@ -177,6 +198,9 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
177
198
|
if (state.provider === 'demo') {
|
|
178
199
|
return 'no account needed';
|
|
179
200
|
}
|
|
201
|
+
if (isRegisteredProviderName(state.provider)) {
|
|
202
|
+
return `served by the plugin that registers ${registeredProviderNameOf(state.provider)}, on its own sign-in`;
|
|
203
|
+
}
|
|
180
204
|
const credential = state.credentials[state.provider];
|
|
181
205
|
if (credential) {
|
|
182
206
|
return credential.type === 'oauth_token'
|
|
@@ -412,7 +436,13 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
412
436
|
? readNonEmptyString(processEnv.STRATUS_API_KEY_ENV)
|
|
413
437
|
?? state.apiKeyEnv
|
|
414
438
|
: undefined;
|
|
415
|
-
|
|
439
|
+
const stored = credentialProviderOf(provider);
|
|
440
|
+
// A contributed provider brings its own sign-in; setup cannot check
|
|
441
|
+
// it and does not claim to.
|
|
442
|
+
if (stored === undefined) {
|
|
443
|
+
return isRegisteredProviderName(provider);
|
|
444
|
+
}
|
|
445
|
+
return state.credentials[stored] !== undefined
|
|
416
446
|
|| readNonEmptyString(processEnv.STRATUS_API_KEY) !== undefined
|
|
417
447
|
|| (keyEnvSelector ? readNonEmptyString(processEnv[String(keyEnvSelector)]) !== undefined : false)
|
|
418
448
|
|| readNonEmptyString(processEnv[defaultKeyEnvFor(provider)]) !== undefined;
|
|
@@ -503,7 +533,8 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
503
533
|
// provider, wherever the default currently points.
|
|
504
534
|
const listed = available.find((entry) => entry.id === typed);
|
|
505
535
|
const inferred = listed?.provider
|
|
506
|
-
?? (state.provider
|
|
536
|
+
?? credentialProviderOf(state.provider)
|
|
537
|
+
?? available[0].provider;
|
|
507
538
|
return { provider: inferred, id: typed };
|
|
508
539
|
};
|
|
509
540
|
let choice;
|
|
@@ -611,8 +642,9 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
611
642
|
const name = await prompter.ask('Name your agent (Enter to have one generated): ');
|
|
612
643
|
const instructions = await prompter.ask('Describe their personality in a sentence or two (Enter for a starter you can edit later): ');
|
|
613
644
|
const persona = instructions || DEFAULT_SOUL_STARTER;
|
|
645
|
+
const pinnedModel = state.model ?? defaultModelFor(state.provider);
|
|
614
646
|
const pin = state.provider !== 'demo'
|
|
615
|
-
? { provider: state.provider, model:
|
|
647
|
+
? { provider: state.provider, ...(pinnedModel !== undefined ? { model: pinnedModel } : {}) }
|
|
616
648
|
: {};
|
|
617
649
|
const claimed = await claimSoulFile(env, { ...(name ? { name } : {}), instructions: persona }, (agent) => formatSoul({ agent, ...pin }), (message) => writeLine(streams.stdout, message));
|
|
618
650
|
const { agent, soulPath } = claimed;
|
|
@@ -626,7 +658,13 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
626
658
|
if (!state.fallbackModel || state.provider === 'demo') {
|
|
627
659
|
return undefined;
|
|
628
660
|
}
|
|
629
|
-
const
|
|
661
|
+
const selectedFallback = state.fallbackProvider ?? state.provider;
|
|
662
|
+
if (isRegisteredProviderName(selectedFallback)) {
|
|
663
|
+
// A contributed fallback brings its own sign-in, as a contributed
|
|
664
|
+
// primary does; the test run selects it by name and no more.
|
|
665
|
+
return { provider: selectedFallback, model: state.fallbackModel };
|
|
666
|
+
}
|
|
667
|
+
const fallbackProvider = selectedFallback;
|
|
630
668
|
const envKey = (fallbackProvider === state.provider
|
|
631
669
|
? readNonEmptyString(processEnv.STRATUS_API_KEY)
|
|
632
670
|
: undefined)
|
|
@@ -689,9 +727,25 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
689
727
|
?? defaultKeyEnvFor(state.provider);
|
|
690
728
|
const envKey = readNonEmptyString(processEnv.STRATUS_API_KEY)
|
|
691
729
|
?? readNonEmptyString(processEnv[String(keyEnv)]);
|
|
692
|
-
const
|
|
730
|
+
const storedFor = credentialProviderOf(state.provider);
|
|
731
|
+
const credential = envKey || storedFor === undefined ? undefined : state.credentials[storedFor];
|
|
693
732
|
const boundUrl = credential?.type === 'api_key' ? credential.baseUrl : undefined;
|
|
694
|
-
|
|
733
|
+
if (isRegisteredProviderName(state.provider)) {
|
|
734
|
+
// A contributed provider brings its own sign-in and its own default
|
|
735
|
+
// model; the test run selects it and no more, exactly as a real run
|
|
736
|
+
// resolves it — the configured fallback included, so the test
|
|
737
|
+
// exercises the failover the saved config would perform.
|
|
738
|
+
const fallback = buildTestFallback();
|
|
739
|
+
return {
|
|
740
|
+
provider: state.provider,
|
|
741
|
+
...(state.model ? { model: state.model } : {}),
|
|
742
|
+
...(state.systemPrompt ? { systemPrompt: state.systemPrompt } : {}),
|
|
743
|
+
...(env.fetch ? { fetch: env.fetch } : {}),
|
|
744
|
+
...(soul ? { soul } : {}),
|
|
745
|
+
...(fallback ? { fallback } : {}),
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const model = state.model ?? builtInDefaultModel(state.provider);
|
|
695
749
|
if (state.provider === 'anthropic') {
|
|
696
750
|
const apiKey = envKey ?? (credential?.type === 'api_key' ? credential.value : undefined);
|
|
697
751
|
const authToken = credential?.type === 'oauth_token' ? credential.value : undefined;
|
|
@@ -1039,7 +1093,7 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
1039
1093
|
const { manifest, directory } = await readPluginManifest(name, {
|
|
1040
1094
|
resolve: (target) => import.meta.resolve(target),
|
|
1041
1095
|
});
|
|
1042
|
-
await preflightPlugin(manifest, directory, block
|
|
1096
|
+
await preflightPlugin(manifest, directory, block);
|
|
1043
1097
|
return undefined;
|
|
1044
1098
|
}
|
|
1045
1099
|
catch (error) {
|
|
@@ -2135,8 +2189,9 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
2135
2189
|
// below are objects, and a `Record<string, string | boolean>` was what
|
|
2136
2190
|
// made dropping them the path of least resistance.
|
|
2137
2191
|
const config = { provider: state.provider };
|
|
2138
|
-
|
|
2139
|
-
|
|
2192
|
+
const savedModel = state.model ?? defaultModelFor(state.provider);
|
|
2193
|
+
if (state.provider !== 'demo' && savedModel !== undefined) {
|
|
2194
|
+
config.model = savedModel;
|
|
2140
2195
|
}
|
|
2141
2196
|
if (state.provider === 'openai') {
|
|
2142
2197
|
config.baseUrl = state.baseUrl ?? state.credentials.openai?.baseUrl ?? DEFAULT_OPENAI_BASE_URL;
|
|
@@ -2171,8 +2226,8 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
2171
2226
|
if (state.promptCacheTtl !== undefined) {
|
|
2172
2227
|
config.promptCacheTtl = state.promptCacheTtl;
|
|
2173
2228
|
}
|
|
2174
|
-
// `plugins` and `approvals` have menus above; `api` and
|
|
2175
|
-
// do not and are written back exactly as they were read. Both cases
|
|
2229
|
+
// `plugins` and `approvals` have menus above; `api`, `principals`, and
|
|
2230
|
+
// `slack` do not and are written back exactly as they were read. Both cases
|
|
2176
2231
|
// land here the same way, because the menus edit this state rather
|
|
2177
2232
|
// than the file — so there is nothing to merge, only to not lose.
|
|
2178
2233
|
if (state.plugins !== undefined) {
|
|
@@ -2187,6 +2242,21 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
2187
2242
|
if (state.principals !== undefined) {
|
|
2188
2243
|
config.principals = state.principals;
|
|
2189
2244
|
}
|
|
2245
|
+
if (state.slack !== undefined) {
|
|
2246
|
+
config.slack = state.slack;
|
|
2247
|
+
}
|
|
2248
|
+
if (state.executor !== undefined) {
|
|
2249
|
+
config.executor = state.executor;
|
|
2250
|
+
}
|
|
2251
|
+
if (state.memoryStore !== undefined) {
|
|
2252
|
+
config.memoryStore = state.memoryStore;
|
|
2253
|
+
}
|
|
2254
|
+
if (state.maxTokens !== undefined) {
|
|
2255
|
+
config.maxTokens = state.maxTokens;
|
|
2256
|
+
}
|
|
2257
|
+
if (state.maxTurns !== undefined) {
|
|
2258
|
+
config.maxTurns = state.maxTurns;
|
|
2259
|
+
}
|
|
2190
2260
|
await saveConfigFile(configPath, config);
|
|
2191
2261
|
writeLine(streams.stdout);
|
|
2192
2262
|
writeLine(streams.stdout, `Wrote ${configPath}`);
|
|
@@ -2287,8 +2357,8 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
2287
2357
|
// would make `stratus run` behave differently from what was just saved.
|
|
2288
2358
|
const conflicts = [
|
|
2289
2359
|
detectEnvOverride('STRATUS_PROVIDER', state.provider, '--provider'),
|
|
2290
|
-
...(state.provider !== 'demo'
|
|
2291
|
-
? [detectEnvOverride('STRATUS_MODEL', state.model ?? defaultModelFor(state.provider), '--model')]
|
|
2360
|
+
...(state.provider !== 'demo' && (state.model ?? defaultModelFor(state.provider)) !== undefined
|
|
2361
|
+
? [detectEnvOverride('STRATUS_MODEL', String(state.model ?? defaultModelFor(state.provider)), '--model')]
|
|
2292
2362
|
: []),
|
|
2293
2363
|
...(state.provider === 'openai'
|
|
2294
2364
|
? [detectEnvOverride('STRATUS_BASE_URL', state.baseUrl ?? DEFAULT_OPENAI_BASE_URL, '--base-url')]
|
|
@@ -2311,7 +2381,7 @@ export const runSetup = async (command, streams, env = {}) => {
|
|
|
2311
2381
|
else if (readNonEmptyString(processEnv.STRATUS_API_KEY)) {
|
|
2312
2382
|
writeLine(streams.stdout, 'STRATUS_API_KEY is exported and takes precedence over your saved sign-in. You are ready to go. Try:');
|
|
2313
2383
|
}
|
|
2314
|
-
else if (state.credentials[state.provider]) {
|
|
2384
|
+
else if (isRegisteredProviderName(state.provider) || state.credentials[credentialProviderOf(state.provider) ?? 'anthropic']) {
|
|
2315
2385
|
writeLine(streams.stdout, `You are ${signInSummary()} — ready to go. Try:`);
|
|
2316
2386
|
}
|
|
2317
2387
|
else {
|