@open-agent-toolkit/cli 0.0.34 → 0.0.36
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/assets/docs/cli-utilities/tool-packs.md +8 -1
- package/assets/docs/provider-sync/manifest-and-drift.md +2 -0
- package/assets/public-package-versions.json +4 -4
- package/dist/commands/init/tools/core/index.d.ts.map +1 -1
- package/dist/commands/init/tools/core/index.js +7 -1
- package/dist/commands/init/tools/docs/index.d.ts.map +1 -1
- package/dist/commands/init/tools/docs/index.js +4 -2
- package/dist/commands/init/tools/ideas/index.d.ts.map +1 -1
- package/dist/commands/init/tools/ideas/index.js +8 -2
- package/dist/commands/init/tools/index.d.ts +13 -2
- package/dist/commands/init/tools/index.d.ts.map +1 -1
- package/dist/commands/init/tools/index.js +321 -83
- package/dist/commands/init/tools/install-state.d.ts +10 -0
- package/dist/commands/init/tools/install-state.d.ts.map +1 -0
- package/dist/commands/init/tools/install-state.js +36 -0
- package/dist/commands/init/tools/project-management/index.d.ts.map +1 -1
- package/dist/commands/init/tools/project-management/index.js +6 -0
- package/dist/commands/init/tools/research/index.d.ts.map +1 -1
- package/dist/commands/init/tools/research/index.js +8 -3
- package/dist/commands/init/tools/utility/index.d.ts.map +1 -1
- package/dist/commands/init/tools/utility/index.js +4 -2
- package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
- package/dist/commands/init/tools/workflows/index.js +8 -2
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +27 -5
- package/dist/commands/sync/sync.types.d.ts +1 -0
- package/dist/commands/sync/sync.types.d.ts.map +1 -1
- package/dist/commands/tools/install/index.d.ts +2 -1
- package/dist/commands/tools/install/index.d.ts.map +1 -1
- package/dist/commands/tools/install/index.js +26 -8
- package/dist/commands/tools/shared/auto-sync.d.ts +4 -1
- package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
- package/dist/commands/tools/shared/auto-sync.js +7 -2
- package/dist/commands/tools/shared/install-sync-context.d.ts +9 -0
- package/dist/commands/tools/shared/install-sync-context.d.ts.map +1 -0
- package/dist/commands/tools/shared/install-sync-context.js +45 -0
- package/dist/engine/compute-plan.d.ts +2 -1
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +8 -1
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rm, unlink } from 'node:fs/promises';
|
|
1
2
|
import { join } from 'node:path';
|
|
2
3
|
import { buildCommandContext, } from '../../../app/command-context.js';
|
|
3
4
|
import { copyDirWithStatus } from '../../init/tools/shared/copy-helpers.js';
|
|
@@ -6,6 +7,8 @@ import { addLocalPaths } from '../../local/manage.js';
|
|
|
6
7
|
import { removeAgentsMdSection, upsertAgentsMdSection, } from '../../shared/agents-md.js';
|
|
7
8
|
import { selectManyWithAbort, selectWithAbort, } from '../../shared/shared.prompts.js';
|
|
8
9
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
10
|
+
import { canonicalPathsForPacks, setInstalledCanonicalPaths, } from '../../tools/shared/install-sync-context.js';
|
|
11
|
+
import { scanTools } from '../../tools/shared/scan-tools.js';
|
|
9
12
|
import { readOatConfig, resolveLocalPaths, writeOatConfig, } from '../../../config/oat-config.js';
|
|
10
13
|
import { resolveAssetsRoot } from '../../../fs/assets.js';
|
|
11
14
|
import { resolveProjectRoot, resolveScopeRoot } from '../../../fs/paths.js';
|
|
@@ -13,38 +16,56 @@ import { Command } from 'commander';
|
|
|
13
16
|
import { createInitToolsCoreCommand } from './core/index.js';
|
|
14
17
|
import { installCore as defaultInstallCore, } from './core/install-core.js';
|
|
15
18
|
import { createInitToolsDocsCommand } from './docs/index.js';
|
|
16
|
-
import {
|
|
19
|
+
import { installDocs as defaultInstallDocs, } from './docs/install-docs.js';
|
|
17
20
|
import { createInitToolsIdeasCommand } from './ideas/index.js';
|
|
18
21
|
import { installIdeas as defaultInstallIdeas, } from './ideas/install-ideas.js';
|
|
22
|
+
import { buildPackInstallStateMap, } from './install-state.js';
|
|
19
23
|
import { createInitToolsProjectManagementCommand } from './project-management/index.js';
|
|
20
24
|
import { installProjectManagement as defaultInstallProjectManagement, } from './project-management/install-project-management.js';
|
|
21
25
|
import { createInitToolsResearchCommand } from './research/index.js';
|
|
22
|
-
import { installResearch as defaultInstallResearch,
|
|
26
|
+
import { installResearch as defaultInstallResearch, } from './research/install-research.js';
|
|
27
|
+
import { DOCS_SKILLS, IDEA_SKILLS, RESEARCH_AGENTS, RESEARCH_SKILLS, UTILITY_SKILLS, } from './shared/skill-manifest.js';
|
|
23
28
|
import { createInitToolsUtilityCommand } from './utility/index.js';
|
|
24
|
-
import { installUtility as defaultInstallUtility,
|
|
29
|
+
import { installUtility as defaultInstallUtility, } from './utility/install-utility.js';
|
|
25
30
|
import { createInitToolsWorkflowsCommand } from './workflows/index.js';
|
|
26
31
|
import { installWorkflows as defaultInstallWorkflows, } from './workflows/install-workflows.js';
|
|
27
32
|
function formatVersionForDisplay(version) {
|
|
28
33
|
return version ?? '(unversioned)';
|
|
29
34
|
}
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
{ label: 'Workflows [project]', value: 'workflows', checked: true },
|
|
40
|
-
{ label: 'Utility [project|user]', value: 'utility', checked: true },
|
|
41
|
-
{ label: 'Research [project|user]', value: 'research', checked: true },
|
|
35
|
+
const ALL_TOOL_PACKS = [
|
|
36
|
+
'core',
|
|
37
|
+
'ideas',
|
|
38
|
+
'docs',
|
|
39
|
+
'workflows',
|
|
40
|
+
'utility',
|
|
41
|
+
'project-management',
|
|
42
|
+
'research',
|
|
42
43
|
];
|
|
44
|
+
const USER_ELIGIBLE_PACK_MEMBERS = {
|
|
45
|
+
ideas: {
|
|
46
|
+
skills: IDEA_SKILLS,
|
|
47
|
+
agents: [],
|
|
48
|
+
},
|
|
49
|
+
docs: {
|
|
50
|
+
skills: DOCS_SKILLS,
|
|
51
|
+
agents: [],
|
|
52
|
+
},
|
|
53
|
+
utility: {
|
|
54
|
+
skills: UTILITY_SKILLS,
|
|
55
|
+
agents: [],
|
|
56
|
+
},
|
|
57
|
+
research: {
|
|
58
|
+
skills: RESEARCH_SKILLS,
|
|
59
|
+
agents: RESEARCH_AGENTS,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
let lastRunInitToolsMetadata = null;
|
|
43
63
|
const DEFAULT_DEPENDENCIES = {
|
|
44
64
|
buildCommandContext,
|
|
45
65
|
resolveProjectRoot,
|
|
46
66
|
resolveScopeRoot,
|
|
47
67
|
resolveAssetsRoot,
|
|
68
|
+
scanTools,
|
|
48
69
|
selectManyWithAbort,
|
|
49
70
|
selectWithAbort,
|
|
50
71
|
installCore: defaultInstallCore,
|
|
@@ -55,6 +76,21 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
55
76
|
installProjectManagement: defaultInstallProjectManagement,
|
|
56
77
|
installResearch: defaultInstallResearch,
|
|
57
78
|
copyDirWithStatus,
|
|
79
|
+
removeDirectory: async (target) => {
|
|
80
|
+
await rm(target, { recursive: true, force: true });
|
|
81
|
+
},
|
|
82
|
+
removeFile: async (target) => {
|
|
83
|
+
try {
|
|
84
|
+
await unlink(target);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
if (!(error instanceof Error) ||
|
|
88
|
+
!('code' in error) ||
|
|
89
|
+
error.code !== 'ENOENT') {
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
58
94
|
addLocalPaths,
|
|
59
95
|
applyGitignore,
|
|
60
96
|
readOatConfig,
|
|
@@ -69,7 +105,120 @@ const USER_ELIGIBLE_PACKS = new Set([
|
|
|
69
105
|
'utility',
|
|
70
106
|
'research',
|
|
71
107
|
]);
|
|
72
|
-
|
|
108
|
+
function isUserEligiblePack(pack) {
|
|
109
|
+
return USER_ELIGIBLE_PACKS.has(pack);
|
|
110
|
+
}
|
|
111
|
+
async function loadInstalledPackStates(projectRoot, userRoot, assetsRoot, dependencies) {
|
|
112
|
+
const [projectTools, userTools] = await Promise.all([
|
|
113
|
+
dependencies.scanTools({
|
|
114
|
+
scope: 'project',
|
|
115
|
+
scopeRoot: projectRoot,
|
|
116
|
+
assetsRoot,
|
|
117
|
+
}),
|
|
118
|
+
dependencies.scanTools({
|
|
119
|
+
scope: 'user',
|
|
120
|
+
scopeRoot: userRoot,
|
|
121
|
+
assetsRoot,
|
|
122
|
+
}),
|
|
123
|
+
]);
|
|
124
|
+
return buildPackInstallStateMap(ALL_TOOL_PACKS, [
|
|
125
|
+
...projectTools,
|
|
126
|
+
...userTools,
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
function formatInstalledLocation(location) {
|
|
130
|
+
switch (location) {
|
|
131
|
+
case 'project':
|
|
132
|
+
return 'project';
|
|
133
|
+
case 'user':
|
|
134
|
+
return 'user';
|
|
135
|
+
case 'both':
|
|
136
|
+
return 'project + user';
|
|
137
|
+
default:
|
|
138
|
+
return 'not installed';
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function buildPackChoices(installedPackStates) {
|
|
142
|
+
return [
|
|
143
|
+
{
|
|
144
|
+
label: `Core [user]${installedPackStates.core.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.core.location)})`}`,
|
|
145
|
+
value: 'core',
|
|
146
|
+
checked: true,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
label: `Ideas [project|user]${installedPackStates.ideas.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.ideas.location)})`}`,
|
|
150
|
+
value: 'ideas',
|
|
151
|
+
checked: true,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
label: `Docs [project|user]${installedPackStates.docs.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.docs.location)})`}`,
|
|
155
|
+
value: 'docs',
|
|
156
|
+
checked: true,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
label: `Project Management [project]${installedPackStates['project-management'].location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates['project-management'].location)})`}`,
|
|
160
|
+
value: 'project-management',
|
|
161
|
+
checked: false,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
label: `Workflows [project]${installedPackStates.workflows.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.workflows.location)})`}`,
|
|
165
|
+
value: 'workflows',
|
|
166
|
+
checked: true,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
label: `Utility [project|user]${installedPackStates.utility.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.utility.location)})`}`,
|
|
170
|
+
value: 'utility',
|
|
171
|
+
checked: true,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: `Research [project|user]${installedPackStates.research.location === 'not-installed' ? '' : ` (installed: ${formatInstalledLocation(installedPackStates.research.location)})`}`,
|
|
175
|
+
value: 'research',
|
|
176
|
+
checked: true,
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
function buildUserScopeChoices(packs, installedPackStates) {
|
|
181
|
+
return packs.map((pack) => {
|
|
182
|
+
const location = installedPackStates[pack].location;
|
|
183
|
+
return {
|
|
184
|
+
label: location === 'not-installed'
|
|
185
|
+
? pack
|
|
186
|
+
: `${pack} (current: ${formatInstalledLocation(location)})`,
|
|
187
|
+
value: pack,
|
|
188
|
+
checked: location === 'user' || location === 'both',
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
async function resolveBothScopeTarget(pack, dependencies, interactive) {
|
|
193
|
+
const selection = await dependencies.selectWithAbort(`${pack} is currently installed in project and user scope. Keep both installs or normalize to user scope?`, [
|
|
194
|
+
{
|
|
195
|
+
label: 'Keep project + user (recommended)',
|
|
196
|
+
value: 'both',
|
|
197
|
+
description: 'Preserve both installed copies',
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
label: 'User only',
|
|
201
|
+
value: 'user',
|
|
202
|
+
description: 'Remove the project-scoped copy',
|
|
203
|
+
},
|
|
204
|
+
], { interactive });
|
|
205
|
+
return selection ?? 'both';
|
|
206
|
+
}
|
|
207
|
+
export function consumeInitToolsRunMetadata() {
|
|
208
|
+
const metadata = lastRunInitToolsMetadata;
|
|
209
|
+
lastRunInitToolsMetadata = null;
|
|
210
|
+
return metadata;
|
|
211
|
+
}
|
|
212
|
+
async function removePackFromScope(pack, root, dependencies) {
|
|
213
|
+
const members = USER_ELIGIBLE_PACK_MEMBERS[pack];
|
|
214
|
+
for (const skill of members.skills) {
|
|
215
|
+
await dependencies.removeDirectory(join(root, '.agents', 'skills', skill));
|
|
216
|
+
}
|
|
217
|
+
for (const agent of members.agents) {
|
|
218
|
+
await dependencies.removeFile(join(root, '.agents', 'agents', agent));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function resolvePackScopes(context, selections, installedPackStates, dependencies) {
|
|
73
222
|
const scopes = {};
|
|
74
223
|
// Workflows is always project-only
|
|
75
224
|
for (const pack of selections) {
|
|
@@ -81,7 +230,7 @@ async function resolvePackScopes(context, selections, dependencies) {
|
|
|
81
230
|
if (selections.includes('core')) {
|
|
82
231
|
scopes.core = 'user';
|
|
83
232
|
}
|
|
84
|
-
const eligiblePacks = selections.filter((pack) =>
|
|
233
|
+
const eligiblePacks = selections.filter((pack) => isUserEligiblePack(pack));
|
|
85
234
|
if (eligiblePacks.length === 0) {
|
|
86
235
|
return scopes;
|
|
87
236
|
}
|
|
@@ -106,31 +255,45 @@ async function resolvePackScopes(context, selections, dependencies) {
|
|
|
106
255
|
return scopes;
|
|
107
256
|
}
|
|
108
257
|
// Interactive: let user pick which packs go to user scope
|
|
109
|
-
const userScopePacks = (await dependencies.selectManyWithAbort('Which packs should install at user scope? (unselected go to project scope)', eligiblePacks.
|
|
110
|
-
label: pack,
|
|
111
|
-
value: pack,
|
|
112
|
-
checked: false,
|
|
113
|
-
})), { interactive: context.interactive })) ?? [];
|
|
258
|
+
const userScopePacks = (await dependencies.selectManyWithAbort('Which packs should install at user scope? (unselected go to project scope)', buildUserScopeChoices(eligiblePacks, installedPackStates), { interactive: context.interactive })) ?? [];
|
|
114
259
|
const userScopeSet = new Set(userScopePacks);
|
|
115
260
|
for (const pack of eligiblePacks) {
|
|
116
|
-
|
|
261
|
+
if (!userScopeSet.has(pack)) {
|
|
262
|
+
scopes[pack] = 'project';
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
scopes[pack] =
|
|
266
|
+
installedPackStates[pack].location === 'both'
|
|
267
|
+
? await resolveBothScopeTarget(pack, dependencies, context.interactive)
|
|
268
|
+
: 'user';
|
|
117
269
|
}
|
|
118
270
|
return scopes;
|
|
119
271
|
}
|
|
120
|
-
function
|
|
272
|
+
function buildInstalledToolsConfig(selectedPacks, installedPackStates, existingTools) {
|
|
273
|
+
const selectedPackSet = new Set(selectedPacks);
|
|
274
|
+
const tools = { ...existingTools };
|
|
275
|
+
for (const pack of ALL_TOOL_PACKS) {
|
|
276
|
+
tools[pack] =
|
|
277
|
+
selectedPackSet.has(pack) ||
|
|
278
|
+
installedPackStates[pack].location !== 'not-installed';
|
|
279
|
+
}
|
|
280
|
+
return tools;
|
|
281
|
+
}
|
|
282
|
+
function reportSuccess(context, packs, syncScopes) {
|
|
121
283
|
if (context.json) {
|
|
122
284
|
context.logger.json({
|
|
123
285
|
status: 'ok',
|
|
124
|
-
|
|
125
|
-
|
|
286
|
+
installedPacks: packs,
|
|
287
|
+
syncScopes,
|
|
126
288
|
});
|
|
127
289
|
return;
|
|
128
290
|
}
|
|
129
|
-
context.logger.info(`Installed tool packs: ${
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
291
|
+
context.logger.info(`Installed tool packs: ${packs.map(({ pack, scope }) => `${pack} (${formatInstalledLocation(scope)})`).join(', ')}`);
|
|
292
|
+
syncScopes.forEach((scope, index) => {
|
|
293
|
+
context.logger.info(`${index === 0 ? 'Run' : 'Also run'}: oat sync --scope ${scope}`);
|
|
294
|
+
});
|
|
295
|
+
if (syncScopes.length === 0) {
|
|
296
|
+
context.logger.info('No sync needed.');
|
|
134
297
|
}
|
|
135
298
|
}
|
|
136
299
|
function reportOutdatedSkills(context, outdatedSkills) {
|
|
@@ -139,7 +302,7 @@ function reportOutdatedSkills(context, outdatedSkills) {
|
|
|
139
302
|
}
|
|
140
303
|
context.logger.info('Outdated skills:');
|
|
141
304
|
for (const skill of outdatedSkills) {
|
|
142
|
-
context.logger.info(` ${skill.name} ${formatVersionForDisplay(skill.installed)} -> ${formatVersionForDisplay(skill.bundled)}`);
|
|
305
|
+
context.logger.info(` ${skill.name} (${skill.targetRoot}) ${formatVersionForDisplay(skill.installed)} -> ${formatVersionForDisplay(skill.bundled)}`);
|
|
143
306
|
}
|
|
144
307
|
}
|
|
145
308
|
async function updateOutdatedSkills(outdatedSkills, assetsRoot, dependencies) {
|
|
@@ -162,7 +325,7 @@ const PACK_DESCRIPTIONS = {
|
|
|
162
325
|
research: 'Research, analysis, verification, and synthesis',
|
|
163
326
|
};
|
|
164
327
|
export function buildToolPacksSectionBody(packs) {
|
|
165
|
-
const userPacks = packs.filter((p) => p.scope === 'user');
|
|
328
|
+
const userPacks = packs.filter((p) => p.scope === 'user' || p.scope === 'both');
|
|
166
329
|
const hasWorkflows = packs.some((p) => p.pack === 'workflows');
|
|
167
330
|
const lines = [
|
|
168
331
|
'## Tool Packs',
|
|
@@ -178,7 +341,11 @@ export function buildToolPacksSectionBody(packs) {
|
|
|
178
341
|
}
|
|
179
342
|
lines.push('', '### Installed Packs', '');
|
|
180
343
|
for (const { pack, scope } of packs) {
|
|
181
|
-
const suffix = scope === 'user'
|
|
344
|
+
const suffix = scope === 'user'
|
|
345
|
+
? ' _(user scope)_'
|
|
346
|
+
: scope === 'both'
|
|
347
|
+
? ' _(project + user scope)_'
|
|
348
|
+
: '';
|
|
182
349
|
lines.push(`- **${pack}** — ${PACK_DESCRIPTIONS[pack]}${suffix}`);
|
|
183
350
|
}
|
|
184
351
|
if (hasWorkflows) {
|
|
@@ -187,66 +354,118 @@ export function buildToolPacksSectionBody(packs) {
|
|
|
187
354
|
return lines.join('\n');
|
|
188
355
|
}
|
|
189
356
|
export async function runInitTools(context, dependencies) {
|
|
357
|
+
lastRunInitToolsMetadata = null;
|
|
190
358
|
try {
|
|
359
|
+
const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
360
|
+
const userRoot = dependencies.resolveScopeRoot('user', context.cwd, context.home);
|
|
361
|
+
const assetsRoot = await dependencies.resolveAssetsRoot();
|
|
362
|
+
const initialPackStates = await loadInstalledPackStates(projectRoot, userRoot, assetsRoot, dependencies);
|
|
191
363
|
const selectedPacks = context.interactive
|
|
192
|
-
? ((await dependencies.selectManyWithAbort('Select tool packs to install',
|
|
364
|
+
? ((await dependencies.selectManyWithAbort('Select tool packs to install', buildPackChoices(initialPackStates), { interactive: context.interactive })) ?? [])
|
|
193
365
|
: ['core', 'ideas', 'docs', 'workflows', 'utility', 'research'];
|
|
194
366
|
if (!context.interactive) {
|
|
195
367
|
selectedPacks.push('project-management');
|
|
196
368
|
}
|
|
197
369
|
if (selectedPacks.length === 0) {
|
|
370
|
+
lastRunInitToolsMetadata = { affectedScopes: [] };
|
|
198
371
|
if (!context.json) {
|
|
199
372
|
context.logger.info('No tool packs selected.');
|
|
200
373
|
}
|
|
201
374
|
process.exitCode = 0;
|
|
202
375
|
return [];
|
|
203
376
|
}
|
|
204
|
-
const
|
|
205
|
-
const userRoot = dependencies.resolveScopeRoot('user', context.cwd, context.home);
|
|
206
|
-
const packScopes = await resolvePackScopes(context, selectedPacks, dependencies);
|
|
377
|
+
const packScopes = await resolvePackScopes(context, selectedPacks, initialPackStates, dependencies);
|
|
207
378
|
function packRoot(pack) {
|
|
208
379
|
return packScopes[pack] === 'user' ? userRoot : projectRoot;
|
|
209
380
|
}
|
|
210
|
-
|
|
381
|
+
function packTargets(pack) {
|
|
382
|
+
return packScopes[pack] === 'both'
|
|
383
|
+
? [projectRoot, userRoot]
|
|
384
|
+
: [packRoot(pack)];
|
|
385
|
+
}
|
|
211
386
|
const outdatedSkills = [];
|
|
387
|
+
const affectedScopes = new Set();
|
|
388
|
+
for (const pack of selectedPacks) {
|
|
389
|
+
if (!isUserEligiblePack(pack)) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const desiredScope = packScopes[pack];
|
|
393
|
+
const currentLocation = initialPackStates[pack].location;
|
|
394
|
+
if (desiredScope === 'both') {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (desiredScope === 'user') {
|
|
398
|
+
if (currentLocation === 'project' || currentLocation === 'both') {
|
|
399
|
+
await removePackFromScope(pack, projectRoot, dependencies);
|
|
400
|
+
affectedScopes.add('project');
|
|
401
|
+
}
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (currentLocation === 'user' || currentLocation === 'both') {
|
|
405
|
+
await removePackFromScope(pack, userRoot, dependencies);
|
|
406
|
+
affectedScopes.add('user');
|
|
407
|
+
}
|
|
408
|
+
}
|
|
212
409
|
if (selectedPacks.includes('core')) {
|
|
213
410
|
// Core pack always installs at user scope, regardless of userEligibleScope
|
|
411
|
+
affectedScopes.add('user');
|
|
214
412
|
const coreResult = await dependencies.installCore({
|
|
215
413
|
assetsRoot,
|
|
216
414
|
targetRoot: userRoot,
|
|
217
415
|
});
|
|
218
416
|
for (const skill of coreResult.outdatedSkills) {
|
|
219
|
-
outdatedSkills.push({
|
|
417
|
+
outdatedSkills.push({
|
|
418
|
+
...skill,
|
|
419
|
+
targetRoot: userRoot,
|
|
420
|
+
selectionKey: `${skill.name}:${userRoot}`,
|
|
421
|
+
});
|
|
220
422
|
}
|
|
221
423
|
}
|
|
222
424
|
if (selectedPacks.includes('ideas')) {
|
|
223
|
-
const targetRoot
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
425
|
+
for (const targetRoot of packTargets('ideas')) {
|
|
426
|
+
affectedScopes.add(targetRoot === userRoot ? 'user' : 'project');
|
|
427
|
+
const ideasResult = await dependencies.installIdeas({
|
|
428
|
+
assetsRoot,
|
|
429
|
+
targetRoot,
|
|
430
|
+
});
|
|
431
|
+
for (const skill of ideasResult.outdatedSkills) {
|
|
432
|
+
outdatedSkills.push({
|
|
433
|
+
...skill,
|
|
434
|
+
targetRoot,
|
|
435
|
+
selectionKey: `${skill.name}:${targetRoot}`,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
230
438
|
}
|
|
231
439
|
}
|
|
232
440
|
if (selectedPacks.includes('docs')) {
|
|
233
|
-
const targetRoot
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
441
|
+
for (const targetRoot of packTargets('docs')) {
|
|
442
|
+
affectedScopes.add(targetRoot === userRoot ? 'user' : 'project');
|
|
443
|
+
const docsResult = await dependencies.installDocs({
|
|
444
|
+
assetsRoot,
|
|
445
|
+
targetRoot,
|
|
446
|
+
skills: [...DOCS_SKILLS],
|
|
447
|
+
});
|
|
448
|
+
for (const skill of docsResult.outdatedSkills) {
|
|
449
|
+
outdatedSkills.push({
|
|
450
|
+
...skill,
|
|
451
|
+
targetRoot,
|
|
452
|
+
selectionKey: `${skill.name}:${targetRoot}`,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
241
455
|
}
|
|
242
456
|
}
|
|
243
457
|
if (selectedPacks.includes('workflows')) {
|
|
458
|
+
affectedScopes.add('project');
|
|
244
459
|
const workflowsResult = await dependencies.installWorkflows({
|
|
245
460
|
assetsRoot,
|
|
246
461
|
targetRoot: projectRoot,
|
|
247
462
|
});
|
|
248
463
|
for (const skill of workflowsResult.outdatedSkills) {
|
|
249
|
-
outdatedSkills.push({
|
|
464
|
+
outdatedSkills.push({
|
|
465
|
+
...skill,
|
|
466
|
+
targetRoot: projectRoot,
|
|
467
|
+
selectionKey: `${skill.name}:${projectRoot}`,
|
|
468
|
+
});
|
|
250
469
|
}
|
|
251
470
|
const resolvedRoot = workflowsResult.resolvedProjectsRoot || '.oat/projects/shared';
|
|
252
471
|
const projectsBase = resolvedRoot.replace(/\/[^/]+$/, '');
|
|
@@ -285,47 +504,64 @@ export async function runInitTools(context, dependencies) {
|
|
|
285
504
|
}
|
|
286
505
|
}
|
|
287
506
|
if (selectedPacks.includes('utility')) {
|
|
288
|
-
const targetRoot
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
507
|
+
for (const targetRoot of packTargets('utility')) {
|
|
508
|
+
affectedScopes.add(targetRoot === userRoot ? 'user' : 'project');
|
|
509
|
+
const utilityResult = await dependencies.installUtility({
|
|
510
|
+
assetsRoot,
|
|
511
|
+
targetRoot,
|
|
512
|
+
skills: [...UTILITY_SKILLS],
|
|
513
|
+
});
|
|
514
|
+
for (const skill of utilityResult.outdatedSkills) {
|
|
515
|
+
outdatedSkills.push({
|
|
516
|
+
...skill,
|
|
517
|
+
targetRoot,
|
|
518
|
+
selectionKey: `${skill.name}:${targetRoot}`,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
296
521
|
}
|
|
297
522
|
}
|
|
298
523
|
if (selectedPacks.includes('project-management')) {
|
|
299
524
|
const targetRoot = projectRoot;
|
|
525
|
+
affectedScopes.add('project');
|
|
300
526
|
const projectManagementResult = await dependencies.installProjectManagement({
|
|
301
527
|
assetsRoot,
|
|
302
528
|
targetRoot,
|
|
303
529
|
});
|
|
304
530
|
for (const skill of projectManagementResult.outdatedSkills) {
|
|
305
|
-
outdatedSkills.push({
|
|
531
|
+
outdatedSkills.push({
|
|
532
|
+
...skill,
|
|
533
|
+
targetRoot,
|
|
534
|
+
selectionKey: `${skill.name}:${targetRoot}`,
|
|
535
|
+
});
|
|
306
536
|
}
|
|
307
537
|
}
|
|
308
538
|
if (selectedPacks.includes('research')) {
|
|
309
|
-
const targetRoot
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
539
|
+
for (const targetRoot of packTargets('research')) {
|
|
540
|
+
affectedScopes.add(targetRoot === userRoot ? 'user' : 'project');
|
|
541
|
+
const researchResult = await dependencies.installResearch({
|
|
542
|
+
assetsRoot,
|
|
543
|
+
targetRoot,
|
|
544
|
+
skills: [...RESEARCH_SKILLS],
|
|
545
|
+
});
|
|
546
|
+
for (const skill of researchResult.outdatedSkills) {
|
|
547
|
+
outdatedSkills.push({
|
|
548
|
+
...skill,
|
|
549
|
+
targetRoot,
|
|
550
|
+
selectionKey: `${skill.name}:${targetRoot}`,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
317
553
|
}
|
|
318
554
|
}
|
|
319
555
|
if (outdatedSkills.length > 0) {
|
|
320
556
|
reportOutdatedSkills(context, outdatedSkills);
|
|
321
557
|
if (context.interactive) {
|
|
322
558
|
const selectedNames = (await dependencies.selectManyWithAbort('Update outdated skills?', outdatedSkills.map((skill) => ({
|
|
323
|
-
label: `${skill.name} (${skill.installed} -> ${skill.bundled})`,
|
|
324
|
-
value: skill.
|
|
559
|
+
label: `${skill.name} (${skill.targetRoot}) (${skill.installed} -> ${skill.bundled})`,
|
|
560
|
+
value: skill.selectionKey,
|
|
325
561
|
checked: true,
|
|
326
562
|
})), { interactive: context.interactive })) ?? [];
|
|
327
563
|
const selectedSet = new Set(selectedNames);
|
|
328
|
-
const selectedOutdated = outdatedSkills.filter((skill) => selectedSet.has(skill.
|
|
564
|
+
const selectedOutdated = outdatedSkills.filter((skill) => selectedSet.has(skill.selectionKey));
|
|
329
565
|
const updatedNames = await updateOutdatedSkills(selectedOutdated, assetsRoot, dependencies);
|
|
330
566
|
if (updatedNames.length > 0) {
|
|
331
567
|
context.logger.info(`Updated outdated skills: ${updatedNames.join(', ')}`);
|
|
@@ -348,17 +584,18 @@ export async function runInitTools(context, dependencies) {
|
|
|
348
584
|
context.logger.info(`AGENTS.md tool packs section ${sectionResult.action}.`);
|
|
349
585
|
}
|
|
350
586
|
const config = await dependencies.readOatConfig(projectRoot);
|
|
351
|
-
const tools =
|
|
352
|
-
for (const pack of selectedPacks) {
|
|
353
|
-
tools[pack] = true;
|
|
354
|
-
}
|
|
587
|
+
const tools = buildInstalledToolsConfig(selectedPacks, initialPackStates, config.tools);
|
|
355
588
|
await dependencies.writeOatConfig(projectRoot, { ...config, tools });
|
|
356
|
-
const
|
|
357
|
-
|
|
589
|
+
const affectedScopesList = [...affectedScopes];
|
|
590
|
+
lastRunInitToolsMetadata = {
|
|
591
|
+
affectedScopes: affectedScopesList,
|
|
592
|
+
};
|
|
593
|
+
reportSuccess(context, packScopeInfo, affectedScopesList);
|
|
358
594
|
process.exitCode = 0;
|
|
359
595
|
return selectedPacks;
|
|
360
596
|
}
|
|
361
597
|
catch (error) {
|
|
598
|
+
lastRunInitToolsMetadata = null;
|
|
362
599
|
const message = error instanceof Error ? error.message : String(error);
|
|
363
600
|
if (context.json) {
|
|
364
601
|
context.logger.json({ status: 'error', message });
|
|
@@ -389,6 +626,7 @@ export function createInitToolsCommand(overrides = {}) {
|
|
|
389
626
|
.addCommand(createInitToolsResearchCommand())
|
|
390
627
|
.action(async (_options, command) => {
|
|
391
628
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
392
|
-
await runInitTools(context, dependencies);
|
|
629
|
+
const selectedPacks = await runInitTools(context, dependencies);
|
|
630
|
+
setInstalledCanonicalPaths(command, canonicalPathsForPacks(selectedPacks));
|
|
393
631
|
});
|
|
394
632
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PackName, ToolInfo } from '../../tools/shared/types.js';
|
|
2
|
+
export type PackInstallLocation = 'not-installed' | 'project' | 'user' | 'both';
|
|
3
|
+
export interface PackInstallState {
|
|
4
|
+
project: boolean;
|
|
5
|
+
user: boolean;
|
|
6
|
+
location: PackInstallLocation;
|
|
7
|
+
}
|
|
8
|
+
export declare function resolvePackInstallLocation(project: boolean, user: boolean): PackInstallLocation;
|
|
9
|
+
export declare function buildPackInstallStateMap<TPack extends PackName>(packs: readonly TPack[], tools: ToolInfo[]): Record<TPack, PackInstallState>;
|
|
10
|
+
//# sourceMappingURL=install-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-state.d.ts","sourceRoot":"","sources":["../../../../src/commands/init/tools/install-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAEvE,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,GACZ,mBAAmB,CAcrB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,QAAQ,EAC7D,KAAK,EAAE,SAAS,KAAK,EAAE,EACvB,KAAK,EAAE,QAAQ,EAAE,GAChB,MAAM,CAAC,KAAK,EAAE,gBAAgB,CAAC,CA8BjC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function resolvePackInstallLocation(project, user) {
|
|
2
|
+
if (project && user) {
|
|
3
|
+
return 'both';
|
|
4
|
+
}
|
|
5
|
+
if (project) {
|
|
6
|
+
return 'project';
|
|
7
|
+
}
|
|
8
|
+
if (user) {
|
|
9
|
+
return 'user';
|
|
10
|
+
}
|
|
11
|
+
return 'not-installed';
|
|
12
|
+
}
|
|
13
|
+
export function buildPackInstallStateMap(packs, tools) {
|
|
14
|
+
const state = Object.fromEntries(packs.map((pack) => [
|
|
15
|
+
pack,
|
|
16
|
+
{
|
|
17
|
+
project: false,
|
|
18
|
+
user: false,
|
|
19
|
+
location: 'not-installed',
|
|
20
|
+
},
|
|
21
|
+
]));
|
|
22
|
+
for (const tool of tools) {
|
|
23
|
+
if (tool.pack === 'custom' || !(tool.pack in state)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const packState = state[tool.pack];
|
|
27
|
+
if (tool.scope === 'project') {
|
|
28
|
+
packState.project = true;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
packState.user = true;
|
|
32
|
+
}
|
|
33
|
+
packState.location = resolvePackInstallLocation(packState.project, packState.user);
|
|
34
|
+
}
|
|
35
|
+
return state;
|
|
36
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/project-management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/commands/init/tools/project-management/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,+BAA+B,EACpC,KAAK,8BAA8B,EACpC,MAAM,8BAA8B,CAAC;AAMtC,UAAU,sCAAsC;IAC9C,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,wBAAwB,EAAE,CACxB,OAAO,EAAE,+BAA+B,KACrC,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC9C;AASD,wBAAgB,uCAAuC,CACrD,SAAS,GAAE,OAAO,CAAC,sCAAsC,CAAM,GAC9D,OAAO,CAmET"}
|