@ai-outfitter/outfitter 1.14.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/code/pi-extension/src/outfitter-extension.js +155 -65
- package/code/pi-extension/src/outfitter-runtime-extension.js +41 -25
- package/dist/cli/OutfitterCli.js +2 -0
- package/dist/cli/OutfitterCli.js.map +1 -1
- package/dist/cli/commands/DumpCommand.js +2 -2
- package/dist/cli/commands/DumpCommand.js.map +1 -1
- package/dist/cli/commands/LinkCommand.d.ts +27 -0
- package/dist/cli/commands/LinkCommand.js +137 -0
- package/dist/cli/commands/LinkCommand.js.map +1 -0
- package/dist/cli/commands/ListCommand.d.ts +2 -0
- package/dist/cli/commands/ListCommand.js +32 -8
- package/dist/cli/commands/ListCommand.js.map +1 -1
- package/dist/cli/commands/PiRuntimeLaunch.d.ts +6 -0
- package/dist/cli/commands/PiRuntimeLaunch.js +11 -1
- package/dist/cli/commands/PiRuntimeLaunch.js.map +1 -1
- package/dist/cli/commands/RunAgentCommand.d.ts +2 -0
- package/dist/cli/commands/RunAgentCommand.js +36 -14
- package/dist/cli/commands/RunAgentCommand.js.map +1 -1
- package/dist/cli/commands/SetupCommand.d.ts +22 -1
- package/dist/cli/commands/SetupCommand.js +97 -8
- package/dist/cli/commands/SetupCommand.js.map +1 -1
- package/dist/cli/commands/ValidateCommand.js +4 -1
- package/dist/cli/commands/ValidateCommand.js.map +1 -1
- package/dist/cli.js +14 -6
- package/dist/cli.js.map +1 -1
- package/dist/composer/Chain.d.ts +10 -0
- package/dist/composer/Chain.js +47 -0
- package/dist/composer/Chain.js.map +1 -0
- package/dist/composer/Composer.d.ts +6 -0
- package/dist/composer/Composer.js +42 -141
- package/dist/composer/Composer.js.map +1 -1
- package/dist/composer/Composition.d.ts +16 -0
- package/dist/composer/Defaults.d.ts +33 -0
- package/dist/composer/Defaults.js +103 -0
- package/dist/composer/Defaults.js.map +1 -0
- package/dist/composer/Mcp.d.ts +3 -0
- package/dist/composer/Mcp.js +68 -0
- package/dist/composer/Mcp.js.map +1 -0
- package/dist/dump/Dump.d.ts +2 -1
- package/dist/dump/Dump.js +67 -4
- package/dist/dump/Dump.js.map +1 -1
- package/dist/dump/WorkflowDump.d.ts +9 -1
- package/dist/dump/WorkflowDump.js +7 -3
- package/dist/dump/WorkflowDump.js.map +1 -1
- package/dist/links/HarnessHome.d.ts +15 -0
- package/dist/links/HarnessHome.js +23 -0
- package/dist/links/HarnessHome.js.map +1 -0
- package/dist/links/HarnessLinkApply.d.ts +26 -0
- package/dist/links/HarnessLinkApply.js +356 -0
- package/dist/links/HarnessLinkApply.js.map +1 -0
- package/dist/links/HarnessLinkPlan.d.ts +70 -0
- package/dist/links/HarnessLinkPlan.js +224 -0
- package/dist/links/HarnessLinkPlan.js.map +1 -0
- package/dist/links/HarnessMcp.d.ts +9 -0
- package/dist/links/HarnessMcp.js +67 -0
- package/dist/links/HarnessMcp.js.map +1 -0
- package/dist/projection/CodexSettings.d.ts +3 -0
- package/dist/projection/CodexSettings.js +17 -0
- package/dist/projection/CodexSettings.js.map +1 -0
- package/dist/projection/Materialize.d.ts +20 -2
- package/dist/projection/Materialize.js +66 -33
- package/dist/projection/Materialize.js.map +1 -1
- package/dist/projection/ProjectHarness.js +58 -14
- package/dist/projection/ProjectHarness.js.map +1 -1
- package/dist/projection/Projection.d.ts +3 -1
- package/dist/resolver/ResolverValidation.d.ts +5 -0
- package/dist/resolver/ResolverValidation.js +45 -10
- package/dist/resolver/ResolverValidation.js.map +1 -1
- package/dist/resolver/WorkflowDefinition.d.ts +10 -0
- package/dist/resolver/WorkflowDefinition.js.map +1 -1
- package/dist/resolver/WorkflowOutput.d.ts +9 -0
- package/dist/resolver/WorkflowOutput.js +40 -0
- package/dist/resolver/WorkflowOutput.js.map +1 -0
- package/dist/schemas/settings.schema.json +48 -1
- package/dist/schemas/workflow.schema.json +26 -0
- package/dist/settings/Settings.d.ts +22 -0
- package/dist/settings/Settings.js +14 -0
- package/dist/settings/Settings.js.map +1 -1
- package/dist/settings/SettingsLoader.js +17 -0
- package/dist/settings/SettingsLoader.js.map +1 -1
- package/dist/settings/SettingsMerger.js +37 -0
- package/dist/settings/SettingsMerger.js.map +1 -1
- package/dist/setup/DefaultCatalog.d.ts +4 -2
- package/dist/setup/DefaultCatalog.js +5 -3
- package/dist/setup/DefaultCatalog.js.map +1 -1
- package/dist/setup/Setup.d.ts +11 -2
- package/dist/setup/Setup.js +51 -39
- package/dist/setup/Setup.js.map +1 -1
- package/dist/version/NodeVersionGuard.d.ts +13 -0
- package/dist/version/NodeVersionGuard.js +50 -0
- package/dist/version/NodeVersionGuard.js.map +1 -0
- package/docs/architecture/state_writeback_strategy.md +1 -1
- package/docs/documentation/README.md +1 -1
- package/docs/documentation/catalogs.md +36 -1
- package/docs/documentation/cli.md +42 -7
- package/docs/documentation/conventions.md +1 -1
- package/docs/documentation/dump-and-bake.md +1 -1
- package/docs/documentation/getting-started.md +4 -2
- package/docs/documentation/linking-harnesses.md +88 -0
- package/docs/documentation/local-development.md +5 -7
- package/docs/documentation/migration.md +1 -1
- package/docs/documentation/settings.md +68 -3
- package/docs/documentation/state.md +1 -1
- package/docs/documentation/support-matrix.md +3 -1
- package/docs/documentation/switching-to-outfitter.md +1 -1
- package/docs/documentation/usecases/shared-conventions.md +1 -1
- package/package.json +2 -1
- package/src/schemas/settings.schema.json +48 -1
- package/src/schemas/workflow.schema.json +26 -0
- package/docs/documentation/porting-claude.md +0 -58
package/README.md
CHANGED
|
@@ -24,6 +24,9 @@ For the full argument, read the [Philosophy](./docs/philosophy.md).
|
|
|
24
24
|
|
|
25
25
|
## Quick start
|
|
26
26
|
|
|
27
|
+
Requires Node 22.19 or newer (the bundled Pi's floor). Older Node installs without error but
|
|
28
|
+
crashes when Pi starts, so Outfitter refuses to run and prints an upgrade hint instead.
|
|
29
|
+
|
|
27
30
|
Run without installing:
|
|
28
31
|
|
|
29
32
|
```bash
|
|
@@ -67,10 +70,11 @@ mcp: [github]
|
|
|
67
70
|
default_agent: engineer
|
|
68
71
|
```
|
|
69
72
|
|
|
70
|
-
`outfitter setup`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
`
|
|
73
|
+
`outfitter setup` runs the Pi-native walkthrough on top of `.agents`: choose a profile from the
|
|
74
|
+
default Outfitter catalog or import a different `.agents` catalog, then pick the home/project target
|
|
75
|
+
and default CLI agent. For a custom profile, write `.agents/agents/<id>/agent.md` and set
|
|
76
|
+
`default_agent`. The default picker is fetched from the immutable
|
|
77
|
+
`ai-outfitter/community-profiles` Release Please tag pinned by Outfitter—never from a sibling checkout.
|
|
74
78
|
Managed porting and persistent harness symlinks are deferred to
|
|
75
79
|
[#187](https://github.com/ai-outfitter/outfitter/issues/187).
|
|
76
80
|
|
|
@@ -8,6 +8,9 @@ const OUTFITTER_AGENT_CHOICES = '__OUTFITTER_AGENT_CHOICES__';
|
|
|
8
8
|
const OUTFITTER_CURRENT_DEFAULT = '__OUTFITTER_CURRENT_DEFAULT__';
|
|
9
9
|
const OUTFITTER_SETUP_SOURCE_URI = '__OUTFITTER_SETUP_SOURCE_URI__';
|
|
10
10
|
const OUTFITTER_AUTO_OPEN = '__OUTFITTER_AUTO_OPEN__';
|
|
11
|
+
// The offline placeholder provider the CLI gives this setup shell so Pi starts cleanly; it is not a
|
|
12
|
+
// real model provider and never counts as one.
|
|
13
|
+
const OUTFITTER_SETUP_PROVIDER = '__OUTFITTER_SETUP_PROVIDER__';
|
|
11
14
|
const OUTFITTER_ASCII_ART = [
|
|
12
15
|
'▄▄▄▄▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄',
|
|
13
16
|
'███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▀▀▀ ███ ███',
|
|
@@ -21,6 +24,28 @@ const OUTFITTER_ASCII_GRADIENT = ['success', 'accent', 'text', 'muted', 'dim'];
|
|
|
21
24
|
const OUTFITTER_PROFILE_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
22
25
|
const OUTFITTER_PLAN_TOOLS = ['read', 'grep', 'find', 'ls'];
|
|
23
26
|
const OUTFITTER_DEFAULT_TOOLS = ['read', 'bash', 'edit', 'write'];
|
|
27
|
+
const OUTFITTER_IMPORT_CHOICE = '__import__';
|
|
28
|
+
const OUTFITTER_MORE_CHOICE = '__more__';
|
|
29
|
+
// Keep this dialog in sync with outfitter-runtime-extension.js, which shows the same prompt for
|
|
30
|
+
// users who already have .agents but no provider.
|
|
31
|
+
const OUTFITTER_PROVIDER_PROMPT = {
|
|
32
|
+
title: [
|
|
33
|
+
'Pi does not have a model provider connected yet.',
|
|
34
|
+
'Connect one now so Outfitter can use Pi. Credentials stay inside Pi.',
|
|
35
|
+
'Press Enter to open /login, or Escape to skip and connect later.',
|
|
36
|
+
],
|
|
37
|
+
items: [
|
|
38
|
+
{
|
|
39
|
+
value: 'connect',
|
|
40
|
+
label: 'Connect a model provider',
|
|
41
|
+
description: 'Opens Pi /login to sign in via OAuth or paste an API key.',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
footer: 'enter connect escape skip',
|
|
45
|
+
};
|
|
46
|
+
const OUTFITTER_LOGIN_POLL_MS = 150;
|
|
47
|
+
// Polls allowed for Pi to open its /login UI after the command is submitted (about three seconds).
|
|
48
|
+
const OUTFITTER_LOGIN_OPEN_POLLS = 20;
|
|
24
49
|
const loadPrivateCatalogOnboarding = () => import('./pi-extension/privateCatalogOnboarding.js');
|
|
25
50
|
|
|
26
51
|
export default function outfitter(pi) {
|
|
@@ -70,16 +95,6 @@ export default function outfitter(pi) {
|
|
|
70
95
|
};
|
|
71
96
|
|
|
72
97
|
const createQuestionUi = (ctx) => ({
|
|
73
|
-
async selectSetupMode() {
|
|
74
|
-
const options = [
|
|
75
|
-
'Use the default Outfitter profile catalog',
|
|
76
|
-
'Create your own profile',
|
|
77
|
-
'Provide a different catalog to import',
|
|
78
|
-
];
|
|
79
|
-
const selected = await ctx.ui.select('How would you like to set up Outfitter?', options);
|
|
80
|
-
if (selected === undefined) return undefined;
|
|
81
|
-
return options.indexOf(selected) === 1 ? 'create' : options.indexOf(selected) === 2 ? 'catalog' : 'default';
|
|
82
|
-
},
|
|
83
98
|
async selectInstallTarget() {
|
|
84
99
|
const items = [
|
|
85
100
|
{
|
|
@@ -96,23 +111,62 @@ export default function outfitter(pi) {
|
|
|
96
111
|
];
|
|
97
112
|
return selectFromItems(ctx, ['Where should Outfitter install these settings?'], items, 'home');
|
|
98
113
|
},
|
|
99
|
-
|
|
100
|
-
|
|
114
|
+
// One screen replaces the old setup-mode and profile questions (#381): the featured catalog
|
|
115
|
+
// profiles first, a "More profiles" row for the rest, then a row that imports a different
|
|
116
|
+
// .agents catalog. The CLI marks featured profiles and orders them; abstract ones never arrive.
|
|
117
|
+
async selectProfileOrImport(profiles, currentDefault) {
|
|
118
|
+
const featured = profiles.filter((profile) => profile.featured === true);
|
|
119
|
+
const others = profiles.filter((profile) => profile.featured !== true);
|
|
120
|
+
const collapsible = featured.length > 0 && others.length > 0;
|
|
121
|
+
const importItem = {
|
|
122
|
+
value: OUTFITTER_IMPORT_CHOICE,
|
|
123
|
+
label: 'Import a different .agents catalog',
|
|
124
|
+
description: 'Point Outfitter at a GitHub repository that holds your own .agents settings.',
|
|
125
|
+
};
|
|
126
|
+
const profileItem = (profile) => ({
|
|
101
127
|
value: profile.id,
|
|
102
128
|
label: formatProfileLabel(profile, currentDefault),
|
|
103
129
|
description: profile.description,
|
|
104
|
-
})
|
|
130
|
+
});
|
|
105
131
|
const title = [
|
|
106
|
-
'Outfitter profile
|
|
132
|
+
'Choose an Outfitter profile',
|
|
107
133
|
'',
|
|
108
|
-
|
|
109
|
-
|
|
134
|
+
profiles.length === 0
|
|
135
|
+
? 'No profiles were found in the default Outfitter catalog. Fix the catalog sync or import a different one.'
|
|
136
|
+
: "Profiles come from the community catalog and are added to your .agents as the default for future 'outfitter' launches.",
|
|
110
137
|
];
|
|
111
|
-
const
|
|
112
|
-
currentDefault
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
138
|
+
const preferred = (candidates) =>
|
|
139
|
+
currentDefault !== undefined && candidates.some((profile) => profile.id === currentDefault)
|
|
140
|
+
? currentDefault
|
|
141
|
+
: candidates.some((profile) => profile.id === 'engineer')
|
|
142
|
+
? 'engineer'
|
|
143
|
+
: (candidates[0]?.id ?? OUTFITTER_IMPORT_CHOICE);
|
|
144
|
+
const showAll = collapsible && currentDefault !== undefined && others.some((profile) => profile.id === currentDefault);
|
|
145
|
+
let items;
|
|
146
|
+
let initialValue;
|
|
147
|
+
if (collapsible && !showAll) {
|
|
148
|
+
items = [
|
|
149
|
+
...featured.map(profileItem),
|
|
150
|
+
{
|
|
151
|
+
value: OUTFITTER_MORE_CHOICE,
|
|
152
|
+
label: 'More profiles (' + others.length + ')',
|
|
153
|
+
description: 'Show the other catalog profiles.',
|
|
154
|
+
},
|
|
155
|
+
importItem,
|
|
156
|
+
];
|
|
157
|
+
initialValue = preferred(featured);
|
|
158
|
+
} else {
|
|
159
|
+
items = [...profiles.map(profileItem), importItem];
|
|
160
|
+
initialValue = preferred(profiles);
|
|
161
|
+
}
|
|
162
|
+
let selected = await selectFromItems(ctx, title, items, initialValue);
|
|
163
|
+
if (selected === OUTFITTER_MORE_CHOICE) {
|
|
164
|
+
// Same picker with every profile; Engineer (or the current default) stays preselected.
|
|
165
|
+
selected = await selectFromItems(ctx, title, [...profiles.map(profileItem), importItem], preferred(profiles));
|
|
166
|
+
}
|
|
167
|
+
if (selected === undefined) return undefined;
|
|
168
|
+
if (selected === OUTFITTER_IMPORT_CHOICE) return { import: true };
|
|
169
|
+
return { profile: profiles.find((profile) => profile.id === selected) };
|
|
116
170
|
},
|
|
117
171
|
async selectCliAgent() {
|
|
118
172
|
const items = [
|
|
@@ -149,6 +203,70 @@ export default function outfitter(pi) {
|
|
|
149
203
|
notify: (message, type = 'info') => ctx.ui.notify(message, type),
|
|
150
204
|
});
|
|
151
205
|
|
|
206
|
+
// Real providers only: the CLI stamps a placeholder provider into this setup shell so Pi starts
|
|
207
|
+
// without a login warning, and that placeholder must never satisfy the provider check.
|
|
208
|
+
const countConnectedModels = async (ctx) => {
|
|
209
|
+
if (ctx.modelRegistry === undefined || typeof ctx.modelRegistry.getAvailable !== 'function') return 0;
|
|
210
|
+
try {
|
|
211
|
+
const available = await ctx.modelRegistry.getAvailable();
|
|
212
|
+
return Array.isArray(available)
|
|
213
|
+
? available.filter((model) => model?.provider !== OUTFITTER_SETUP_PROVIDER).length
|
|
214
|
+
: 0;
|
|
215
|
+
} catch {
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Submits /login and resolves 'connected' once a real provider is available, or 'cancelled' when
|
|
221
|
+
// the user leaves Pi's login UI without one. Pi emits no auth event and keeps the placeholder
|
|
222
|
+
// model selected after a login (so `model_select` never fires here); completion is observed
|
|
223
|
+
// through the model registry, which Pi refreshes right after saving credentials, and abandonment
|
|
224
|
+
// through focus returning to the editor after the login UI was shown.
|
|
225
|
+
const openLoginAndWait = (ctx) =>
|
|
226
|
+
ctx.ui.custom(
|
|
227
|
+
(tui, _theme, _keybindings, done) => {
|
|
228
|
+
let editor;
|
|
229
|
+
let loginUiSeen = false;
|
|
230
|
+
let polls = 0;
|
|
231
|
+
const poll = async () => {
|
|
232
|
+
if ((await countConnectedModels(ctx)) > 0) return done('connected');
|
|
233
|
+
polls += 1;
|
|
234
|
+
if (tui.focusedComponent !== editor) loginUiSeen = true;
|
|
235
|
+
else if (loginUiSeen || polls >= OUTFITTER_LOGIN_OPEN_POLLS) return done('cancelled');
|
|
236
|
+
setTimeout(poll, OUTFITTER_LOGIN_POLL_MS);
|
|
237
|
+
};
|
|
238
|
+
ctx.ui.setEditorText('/login');
|
|
239
|
+
setTimeout(() => {
|
|
240
|
+
editor = tui.focusedComponent;
|
|
241
|
+
// Without a focused editor the command cannot be submitted, so there is nothing to wait for.
|
|
242
|
+
if (editor?.handleInput === undefined) return done('cancelled');
|
|
243
|
+
editor.handleInput('\r');
|
|
244
|
+
setTimeout(poll, OUTFITTER_LOGIN_POLL_MS);
|
|
245
|
+
}, 25);
|
|
246
|
+
return { render: () => [], invalidate: () => undefined };
|
|
247
|
+
},
|
|
248
|
+
{ overlay: true, overlayOptions: { nonCapturing: true, visible: () => false } },
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
// Second half of the guided first run: once .agents is written, offer Pi's native /login inside
|
|
252
|
+
// this same session so the relaunched profile starts with credentials in place. Escape skips and
|
|
253
|
+
// the CLI prints the one-line /login hint instead of prompting again.
|
|
254
|
+
const connectModelProvider = async (ctx) => {
|
|
255
|
+
if (ctx.mode !== 'tui' || typeof ctx.ui.custom !== 'function') return 'unavailable';
|
|
256
|
+
if ((await countConnectedModels(ctx)) > 0) return 'available';
|
|
257
|
+
const selected = await selectDescribedOption(
|
|
258
|
+
ctx,
|
|
259
|
+
OUTFITTER_PROVIDER_PROMPT.title,
|
|
260
|
+
OUTFITTER_PROVIDER_PROMPT.items,
|
|
261
|
+
'connect',
|
|
262
|
+
{ footer: OUTFITTER_PROVIDER_PROMPT.footer },
|
|
263
|
+
);
|
|
264
|
+
if (selected === 'connect' && (await openLoginAndWait(ctx)) === 'connected') return 'connected';
|
|
265
|
+
return 'skipped';
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// `run` relaunches the selected profile as soon as this shell exits, so no restart notice here.
|
|
269
|
+
// Only the Pi harness needs a Pi model provider.
|
|
152
270
|
const finish = async (ctx, selection, message) => {
|
|
153
271
|
await writeSetupResult(selection);
|
|
154
272
|
ctx.ui.notify(
|
|
@@ -158,6 +276,9 @@ export default function outfitter(pi) {
|
|
|
158
276
|
].join('\n'),
|
|
159
277
|
'info',
|
|
160
278
|
);
|
|
279
|
+
if (selection.harness === 'pi' && (await connectModelProvider(ctx)) === 'skipped') {
|
|
280
|
+
await writeSetupResult({ ...selection, providerConnection: 'skipped' });
|
|
281
|
+
}
|
|
161
282
|
ctx.shutdown();
|
|
162
283
|
};
|
|
163
284
|
|
|
@@ -166,16 +287,7 @@ export default function outfitter(pi) {
|
|
|
166
287
|
ctx.shutdown();
|
|
167
288
|
};
|
|
168
289
|
|
|
169
|
-
const runDefaultCatalogOnboarding = async (ctx, questionUi) => {
|
|
170
|
-
if (OUTFITTER_AGENT_CHOICES.length === 0) {
|
|
171
|
-
questionUi.notify(
|
|
172
|
-
'No profiles were found in the default Outfitter profile catalog. Fix the catalog sync or provide a different catalog.',
|
|
173
|
-
'error',
|
|
174
|
-
);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
const selectedProfile = await questionUi.selectProfile(OUTFITTER_AGENT_CHOICES, OUTFITTER_CURRENT_DEFAULT);
|
|
178
|
-
if (selectedProfile === undefined) return cancel(ctx);
|
|
290
|
+
const runDefaultCatalogOnboarding = async (ctx, questionUi, selectedProfile) => {
|
|
179
291
|
if (!OUTFITTER_PROFILE_ID_PATTERN.test(selectedProfile.id)) {
|
|
180
292
|
questionUi.notify('Selected profile id is not filesystem-safe; no settings were changed.', 'error');
|
|
181
293
|
return;
|
|
@@ -190,32 +302,6 @@ export default function outfitter(pi) {
|
|
|
190
302
|
[
|
|
191
303
|
"Outfitter saved default profile '" + selectedProfile.id + "' to " + settingsPath + '.',
|
|
192
304
|
'Profile choices were loaded from the default Outfitter profile catalog, not generated locally.',
|
|
193
|
-
"It applies on the next 'outfitter' launch; restart Outfitter to load the selected profile.",
|
|
194
|
-
].join('\n'),
|
|
195
|
-
);
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
const runCreateProfileOnboarding = async (ctx, questionUi) => {
|
|
199
|
-
const enteredProfileId = normalizeInputValue(await questionUi.input('Profile id', 'my_profile'));
|
|
200
|
-
const profileId = enteredProfileId?.replaceAll('_', '-');
|
|
201
|
-
if (!profileId || !OUTFITTER_PROFILE_ID_PATTERN.test(profileId)) {
|
|
202
|
-
questionUi.notify('Profile id is not filesystem-safe; no settings were changed.', 'error');
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
const label = normalizeInputValue(await questionUi.input('Profile label', profileId));
|
|
206
|
-
const choice = await askTargetAndHarness(questionUi);
|
|
207
|
-
if (choice === undefined) return cancel(ctx);
|
|
208
|
-
const { target, harness } = choice;
|
|
209
|
-
const root = installRoot(target);
|
|
210
|
-
const profilePath = root + '/.agents/agents/' + profileId + '/agent.md';
|
|
211
|
-
const settingsPath = root + '/.agents/settings.yml';
|
|
212
|
-
await finish(
|
|
213
|
-
ctx,
|
|
214
|
-
{ setupMode: 'create', agentId: profileId, agentLabel: label, harness, target },
|
|
215
|
-
[
|
|
216
|
-
"Outfitter created profile '" + profileId + "' at " + profilePath + '.',
|
|
217
|
-
'Outfitter saved settings to ' + settingsPath + '.',
|
|
218
|
-
"It applies on the next 'outfitter' launch; restart Outfitter to load the selected profile.",
|
|
219
305
|
].join('\n'),
|
|
220
306
|
);
|
|
221
307
|
};
|
|
@@ -303,11 +389,10 @@ export default function outfitter(pi) {
|
|
|
303
389
|
if (OUTFITTER_SETUP_SOURCE_URI !== undefined) {
|
|
304
390
|
return await runProvidedSourceOnboarding(ctx, questionUi, OUTFITTER_SETUP_SOURCE_URI);
|
|
305
391
|
}
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
if (
|
|
309
|
-
|
|
310
|
-
return await runDefaultCatalogOnboarding(ctx, questionUi);
|
|
392
|
+
const choice = await questionUi.selectProfileOrImport(OUTFITTER_AGENT_CHOICES, OUTFITTER_CURRENT_DEFAULT);
|
|
393
|
+
if (choice === undefined) return cancel(ctx);
|
|
394
|
+
if (choice.import) return await runRemoteSettingsOnboarding(ctx, questionUi);
|
|
395
|
+
return await runDefaultCatalogOnboarding(ctx, questionUi, choice.profile);
|
|
311
396
|
} finally {
|
|
312
397
|
onboardingRunning = false;
|
|
313
398
|
}
|
|
@@ -475,7 +560,9 @@ const selectFromItems = async (ctx, titleLines, items, initialValue) => {
|
|
|
475
560
|
: items.find((item) => item.label === selected)?.value;
|
|
476
561
|
};
|
|
477
562
|
|
|
478
|
-
|
|
563
|
+
// `options.footer` overrides the key legend; by default a single-item list omits "↑↓ navigate"
|
|
564
|
+
// because the arrow keys do nothing there.
|
|
565
|
+
const selectDescribedOption = (ctx, titleLines, items, initialValue, options = {}) =>
|
|
479
566
|
ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
480
567
|
let selectedIndex = Math.max(
|
|
481
568
|
0,
|
|
@@ -535,7 +622,7 @@ const selectDescribedOption = (ctx, titleLines, items, initialValue) =>
|
|
|
535
622
|
renderSelectedItem(prefix, label, selected ? item.description : undefined);
|
|
536
623
|
});
|
|
537
624
|
lines.push('');
|
|
538
|
-
add(theme.fg('dim',
|
|
625
|
+
add(theme.fg('dim', options.footer ?? pickerFooter(items.length)));
|
|
539
626
|
add(theme.fg('accent', '─'.repeat(maxWidth)));
|
|
540
627
|
cachedWidth = maxWidth;
|
|
541
628
|
cachedLines = lines;
|
|
@@ -557,7 +644,10 @@ const selectDescribedOption = (ctx, titleLines, items, initialValue) =>
|
|
|
557
644
|
|
|
558
645
|
const formatProfileLabel = (profile, currentDefault) => {
|
|
559
646
|
const current = profile.id === currentDefault ? ' (current)' : '';
|
|
560
|
-
const recommended = currentDefault === undefined && profile.id === '
|
|
647
|
+
const recommended = currentDefault === undefined && profile.id === 'engineer' ? ' (Recommended)' : '';
|
|
561
648
|
const label = profile.label ? ' — ' + profile.label : '';
|
|
562
649
|
return profile.id + label + current + recommended;
|
|
563
650
|
};
|
|
651
|
+
|
|
652
|
+
const pickerFooter = (itemCount) =>
|
|
653
|
+
(itemCount > 1 ? '↑↓ navigate ' : '') + 'enter select escape/ctrl+c cancel';
|
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
import { Key, matchesKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from '@earendil-works/pi-tui';
|
|
2
2
|
|
|
3
3
|
const OUTFITTER_ACTIVE_PROFILE = '__OUTFITTER_ACTIVE_PROFILE__';
|
|
4
|
+
// 'dialog' offers /login when no provider is connected. 'hint' only prints the one-line reminder;
|
|
5
|
+
// the CLI stamps it when the user skipped the provider step of first-run setup moments earlier.
|
|
6
|
+
const OUTFITTER_PROVIDER_PROMPT_MODE = '__OUTFITTER_PROVIDER_PROMPT_MODE__';
|
|
7
|
+
// Keep this dialog in sync with outfitter-extension.js, which shows the same prompt right after
|
|
8
|
+
// the first-run walkthrough.
|
|
9
|
+
const OUTFITTER_PROVIDER_PROMPT = {
|
|
10
|
+
title: [
|
|
11
|
+
'Pi does not have a model provider connected yet.',
|
|
12
|
+
'Connect one now so Outfitter can use Pi. Credentials stay inside Pi.',
|
|
13
|
+
'Press Enter to open /login, or Escape to skip and connect later.',
|
|
14
|
+
],
|
|
15
|
+
items: [
|
|
16
|
+
{
|
|
17
|
+
value: 'connect',
|
|
18
|
+
label: 'Connect a model provider',
|
|
19
|
+
description: 'Opens Pi /login to sign in via OAuth or paste an API key.',
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
footer: 'enter connect escape skip',
|
|
23
|
+
};
|
|
24
|
+
const OUTFITTER_PROVIDER_HINT = "No model provider connected yet. Run '/login' inside Outfitter to connect one.";
|
|
4
25
|
|
|
5
26
|
// Outfitter runtime extension. Unlike the setup walkthrough extension
|
|
6
27
|
// (outfitter-extension.js), this file is loaded into the real profile pi session. It restores the
|
|
7
|
-
// compact Outfitter + profile header, plus the
|
|
8
|
-
//
|
|
9
|
-
// to pi's native /login command, which persists credentials in
|
|
10
|
-
// a default model in-session.
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// loading it via --extension.
|
|
28
|
+
// compact Outfitter + profile header, plus the "no provider connected yet" sign-in prompt for
|
|
29
|
+
// users who already have .agents but no provider: when pi starts with no models available, it
|
|
30
|
+
// offers to connect one and delegates to pi's native /login command, which persists credentials in
|
|
31
|
+
// pi's own agent directory and selects a default model in-session. First-run users normally
|
|
32
|
+
// connect a provider inside the setup walkthrough instead (OFTR-010.7), so this prompt does not
|
|
33
|
+
// repeat right after setup. The CLI stamps profile metadata into a per-run copy before loading it
|
|
34
|
+
// via --extension.
|
|
15
35
|
|
|
16
36
|
export default function outfitterRuntime(pi) {
|
|
17
37
|
let loginSubmitted = false;
|
|
@@ -48,19 +68,10 @@ export default function outfitterRuntime(pi) {
|
|
|
48
68
|
if (typeof ctx.ui.custom !== 'function') return true;
|
|
49
69
|
const selected = await selectDescribedOption(
|
|
50
70
|
ctx,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
'Connect one now so Outfitter can use Pi.',
|
|
54
|
-
'Credentials stay inside Pi.',
|
|
55
|
-
],
|
|
56
|
-
[
|
|
57
|
-
{
|
|
58
|
-
value: 'connect',
|
|
59
|
-
label: 'Connect a model provider',
|
|
60
|
-
description: 'Open Pi /login to sign in via OAuth or an API key.',
|
|
61
|
-
},
|
|
62
|
-
],
|
|
71
|
+
OUTFITTER_PROVIDER_PROMPT.title,
|
|
72
|
+
OUTFITTER_PROVIDER_PROMPT.items,
|
|
63
73
|
'connect',
|
|
74
|
+
{ footer: OUTFITTER_PROVIDER_PROMPT.footer },
|
|
64
75
|
);
|
|
65
76
|
return selected === 'connect';
|
|
66
77
|
};
|
|
@@ -69,7 +80,10 @@ export default function outfitterRuntime(pi) {
|
|
|
69
80
|
if (loginSubmitted || ctx.mode !== 'tui') return;
|
|
70
81
|
const availableModelCount = await getAvailableModelCount(ctx);
|
|
71
82
|
if (availableModelCount > 0) return;
|
|
72
|
-
if (!(await confirmModelProviderConnection(ctx)))
|
|
83
|
+
if (OUTFITTER_PROVIDER_PROMPT_MODE === 'hint' || !(await confirmModelProviderConnection(ctx))) {
|
|
84
|
+
ctx.ui.notify(OUTFITTER_PROVIDER_HINT, 'warning');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
73
87
|
loginSubmitted = await submitSlashCommand(ctx, '/login');
|
|
74
88
|
};
|
|
75
89
|
|
|
@@ -107,9 +121,9 @@ const setRuntimeHeader = (ctx) => {
|
|
|
107
121
|
};
|
|
108
122
|
|
|
109
123
|
// Renders a described-option picker identical to the setup walkthrough's, so the runtime sign-in
|
|
110
|
-
// prompt matches the rest of the Outfitter UI.
|
|
111
|
-
//
|
|
112
|
-
const selectDescribedOption = (ctx, titleLines, items, initialValue) =>
|
|
124
|
+
// prompt matches the rest of the Outfitter UI. `options.footer` overrides the key legend; by
|
|
125
|
+
// default a single-item list omits "↑↓ navigate" because the arrow keys do nothing there.
|
|
126
|
+
const selectDescribedOption = (ctx, titleLines, items, initialValue, options = {}) =>
|
|
113
127
|
ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
114
128
|
let selectedIndex = Math.max(
|
|
115
129
|
0,
|
|
@@ -169,7 +183,7 @@ const selectDescribedOption = (ctx, titleLines, items, initialValue) =>
|
|
|
169
183
|
renderSelectedItem(prefix, label, selected ? item.description : undefined);
|
|
170
184
|
});
|
|
171
185
|
lines.push('');
|
|
172
|
-
add(theme.fg('dim',
|
|
186
|
+
add(theme.fg('dim', options.footer ?? pickerFooter(items.length)));
|
|
173
187
|
add(theme.fg('accent', '─'.repeat(maxWidth)));
|
|
174
188
|
cachedWidth = maxWidth;
|
|
175
189
|
cachedLines = lines;
|
|
@@ -188,3 +202,5 @@ const selectDescribedOption = (ctx, titleLines, items, initialValue) =>
|
|
|
188
202
|
},
|
|
189
203
|
};
|
|
190
204
|
});
|
|
205
|
+
|
|
206
|
+
const pickerFooter = (itemCount) => (itemCount > 1 ? '↑↓ navigate ' : '') + 'enter select escape/ctrl+c cancel';
|
package/dist/cli/OutfitterCli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { readOutfitterVersion } from '../version/OutfitterVersion.js';
|
|
4
4
|
import { createDumpCommand } from './commands/DumpCommand.js';
|
|
5
|
+
import { createLinkCommand } from './commands/LinkCommand.js';
|
|
5
6
|
import { createListCommand } from './commands/ListCommand.js';
|
|
6
7
|
import { createRunAgentCommand } from './commands/RunAgentCommand.js';
|
|
7
8
|
import { createSetupCommand } from './commands/SetupCommand.js';
|
|
@@ -16,6 +17,7 @@ export const createDefaultCommands = () => [
|
|
|
16
17
|
createListCommand(),
|
|
17
18
|
createValidateCommand(),
|
|
18
19
|
createDumpCommand(),
|
|
20
|
+
createLinkCommand(),
|
|
19
21
|
];
|
|
20
22
|
export const createOutfitterProgram = (commands = createDefaultCommands()) => {
|
|
21
23
|
const program = new Command();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OutfitterCli.js","sourceRoot":"","sources":["../../src/cli/OutfitterCli.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAoB,EAAE,CAAC;IAC1D,qBAAqB,EAAE;IACvB,kBAAkB,EAAE;IACpB,iBAAiB,EAAE;IACnB,oBAAoB,EAAE;IACtB,iBAAiB,EAAE;IACnB,qBAAqB,EAAE;IACvB,iBAAiB,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAqC,qBAAqB,EAAE,EAAW,EAAE;IAC9G,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CAAC,gFAAgF,CAAC;SAC7F,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAEnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"OutfitterCli.js","sourceRoot":"","sources":["../../src/cli/OutfitterCli.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAoB,EAAE,CAAC;IAC1D,qBAAqB,EAAE;IACvB,kBAAkB,EAAE;IACpB,iBAAiB,EAAE;IACnB,oBAAoB,EAAE;IACtB,iBAAiB,EAAE;IACnB,qBAAqB,EAAE;IACvB,iBAAiB,EAAE;IACnB,iBAAiB,EAAE;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,WAAqC,qBAAqB,EAAE,EAAW,EAAE;IAC9G,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CAAC,gFAAgF,CAAC;SAC7F,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAEnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
|
|
@@ -44,8 +44,8 @@ export const executeDumpCommand = (input) => {
|
|
|
44
44
|
}
|
|
45
45
|
const selected = input.workflow ?? resolveAgentSlug(settings, input.agent);
|
|
46
46
|
const result = input.workflow === undefined
|
|
47
|
-
? dumpAgent(set, selected, input.out, input.projectDirectory)
|
|
48
|
-
: dumpWorkflow(set, selected, input.out, input.projectDirectory);
|
|
47
|
+
? dumpAgent(set, selected, input.out, input.projectDirectory, settings.agentDefaults, settings.harnessDefaults)
|
|
48
|
+
: dumpWorkflow(set, selected, input.out, input.projectDirectory, settings.agentDefaults, settings.harnessDefaults);
|
|
49
49
|
const ok = result.errors.length === 0;
|
|
50
50
|
const messages = ok
|
|
51
51
|
? [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DumpCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/DumpCommand.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAGxE,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAuBrF,MAAM,gBAAgB,GAAG,CAAC,QAAkB,EAAE,SAA6B,EAAU,EAAE;IACrF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,QAAQ,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;IAC9F,CAAC;IAED,OAAO,QAAQ,CAAC,YAAY,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,QAAgB,EAAE,QAA2B,EAAqB,EAAE,CAAC,CAAC;IACpG,YAAY,EAAE,EAAE;IAChB,QAAQ,EAAE;QACR,GAAG,QAAQ;QACX,aAAa,QAAQ,8EAA8E;KACpG;IACD,EAAE,EAAE,KAAK;CACV,CAAC,CAAC;AAEH,MAAM,wBAAwB,GAAG,CAAC,KAAgB,EAAQ,EAAE;IAC1D,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;QAC3D,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAgB,EAAqB,EAAE;IACxE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAElG,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnH,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC;IAEtE,wBAAwB,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,SAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC;QAC/E,OAAO,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAE9D,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1D,OAAO;YACL,YAAY,EAAE,EAAE;YAChB,QAAQ,EAAE,CAAC,GAAG,YAAY,EAAE,UAAU,6BAA6B,EAAE,CAAC;YACtE,EAAE,EAAE,KAAK;SACV,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3E,MAAM,MAAM,GACV,KAAK,CAAC,QAAQ,KAAK,SAAS;QAC1B,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"DumpCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/DumpCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { HarnessCommandRunner } from '../../links/HarnessLinkApply.js';
|
|
2
|
+
import type { CommandObject } from './CommandObject.js';
|
|
3
|
+
export interface LinkInput {
|
|
4
|
+
readonly homeDirectory: string;
|
|
5
|
+
readonly projectDirectory: string;
|
|
6
|
+
readonly env: Readonly<Record<string, string | undefined>>;
|
|
7
|
+
readonly harnesses: readonly string[];
|
|
8
|
+
readonly agents: readonly string[];
|
|
9
|
+
readonly workflows: readonly string[];
|
|
10
|
+
readonly all?: boolean;
|
|
11
|
+
readonly dryRun?: boolean;
|
|
12
|
+
readonly remove?: boolean;
|
|
13
|
+
readonly strict?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface LinkResult {
|
|
16
|
+
readonly exitCode: number;
|
|
17
|
+
readonly messages: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export interface LinkCommandDependencies {
|
|
20
|
+
readonly homeDirectory?: string;
|
|
21
|
+
readonly projectDirectory?: string;
|
|
22
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
23
|
+
readonly runHarnessCommand?: HarnessCommandRunner;
|
|
24
|
+
readonly writeLine?: (message: string) => void;
|
|
25
|
+
}
|
|
26
|
+
export declare const executeLinkCommand: (input: LinkInput, run?: HarnessCommandRunner) => LinkResult;
|
|
27
|
+
export declare const createLinkCommand: (dependencies?: LinkCommandDependencies) => CommandObject;
|