argsbarg 6.3.2 → 7.0.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/CHANGELOG.md +17 -3
- package/README.md +2 -2
- package/docs/README.md +2 -2
- package/docs/ai-skills.md +7 -7
- package/docs/bundled-docs.md +2 -2
- package/docs/cli-program.md +4 -4
- package/docs/configure.md +57 -85
- package/docs/developing.md +3 -3
- package/docs/distribution-homebrew.md +22 -23
- package/docs/mcp.md +3 -3
- package/examples/full-example/Formula/full-example.rb +7 -9
- package/examples/full-example/docs/cli-schema.json +48 -60
- package/examples/full-example/docs/cli.md +66 -36
- package/examples/full-example/docs/mcp.md +2 -2
- package/examples/full-example/docs/skill.md +1 -1
- package/examples/full-example/justfile +12 -12
- package/examples/full-example/scripts/formula-shared.ts +7 -13
- package/examples/full-example-json/Formula/full-example-json.rb +7 -9
- package/examples/full-example-json/docs/cli-schema.json +216 -270
- package/examples/full-example-json/docs/cli.md +297 -162
- package/examples/full-example-json/docs/mcp.md +2 -2
- package/examples/full-example-json/docs/skill.md +1 -1
- package/examples/full-example-json/justfile +12 -13
- package/examples/full-example-json/scripts/formula-shared.ts +7 -13
- package/index.d.ts +7 -8
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +21 -28
- package/src/builtins/configure-copy.ts +17 -20
- package/src/builtins/configure.ts +45 -74
- package/src/builtins/dispatch.ts +1 -8
- package/src/builtins/index.ts +1 -1
- package/src/cli-tool/create.ts +3 -1
- package/src/cli-tool/post-create.ts +5 -1
- package/src/config/file.ts +1 -0
- package/src/config/resolve.ts +1 -1
- package/src/configure/artifacts/mcp-config.ts +18 -12
- package/src/configure/artifacts/target-mcp-json.ts +19 -18
- package/src/configure/artifacts/target-skill.ts +8 -3
- package/src/configure/artifacts/targets/agents-mcp.ts +1 -1
- package/src/configure/artifacts/targets/configure.ts +2 -3
- package/src/configure/artifacts/uninstall.ts +5 -1
- package/src/configure/configure.test.ts +45 -113
- package/src/configure/index.ts +64 -354
- package/src/core/types.ts +7 -8
- package/src/docs/docs.test.ts +2 -2
- package/src/docs/mcp-guide.ts +2 -2
- package/src/skill/generate.ts +1 -1
- package/src/skill/install.ts +2 -1
package/src/configure/index.ts
CHANGED
|
@@ -1,193 +1,28 @@
|
|
|
1
1
|
/*
|
|
2
|
-
|
|
2
|
+
`configure install` / `configure uninstall` / `configure status` orchestration.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { displayAppConfigPath, runConfigure } from "../config/bootstrap.ts";
|
|
5
|
+
import { bootstrapAppConfig, displayAppConfigPath, runConfigure } from "../config/bootstrap.ts";
|
|
6
6
|
import { ensureAppConfigFile } from "../config/file.ts";
|
|
7
|
+
import { formatMissingConfigMessage, missingRequiredConfig } from "../config/resolve.ts";
|
|
7
8
|
import type { CliProgram, ConfigureHookContext } from "../core/types.ts";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
printInstallStatus,
|
|
17
|
-
writeInteractiveInstallIntro,
|
|
18
|
-
} from "./artifacts/status.ts";
|
|
19
|
-
import { resolveEffectiveInstallTargets } from "./artifacts/target-effective.ts";
|
|
20
|
-
import { runTargetPreflight } from "./artifacts/target-plan-build.ts";
|
|
21
|
-
import { INSTALL_TARGETS, installTargetForKey } from "./artifacts/target-registry.ts";
|
|
22
|
-
import { buildDetectedSnapshot, buildTargetPlanContext } from "./artifacts/target-scope.ts";
|
|
23
|
-
import type {
|
|
24
|
-
CliInstallArtifactKey,
|
|
25
|
-
InstallAction,
|
|
26
|
-
InstallOpts,
|
|
27
|
-
TargetPlanContext,
|
|
28
|
-
UninstallAction,
|
|
29
|
-
} from "./artifacts/target-types.ts";
|
|
30
|
-
import { buildUninstallPlan, skillDirFromUninstallSummary, uninstallSkillDir } from "./artifacts/uninstall.ts";
|
|
31
|
-
import { artifactPromptLabel, promptTargetAction } from "./prompt.ts";
|
|
32
|
-
|
|
33
|
-
/** True when interactive `configure` should auto-run the app config wizard. */
|
|
9
|
+
import { readPromptLine } from "../prompt.ts";
|
|
10
|
+
import { type InstallPaths, resolveInstallPaths } from "./artifacts/paths.ts";
|
|
11
|
+
import { buildUpdatePlan } from "./artifacts/plan.ts";
|
|
12
|
+
import { installErr, printInstallStatus } from "./artifacts/status.ts";
|
|
13
|
+
import type { InstallAction, InstallOpts, UninstallAction } from "./artifacts/target-types.ts";
|
|
14
|
+
import { buildUninstallPlan } from "./artifacts/uninstall.ts";
|
|
15
|
+
|
|
16
|
+
/** True when `program.appConfig` has wizard entries. */
|
|
34
17
|
export function appConfigHasEntries(program: CliProgram): boolean {
|
|
35
18
|
const entries = program.appConfig?.entries;
|
|
36
19
|
return !!entries && Object.keys(entries).length > 0;
|
|
37
20
|
}
|
|
38
21
|
|
|
39
|
-
|
|
40
|
-
export interface ConfigureOpts {
|
|
41
|
-
refresh?: boolean;
|
|
42
|
-
removeAll?: boolean;
|
|
43
|
-
removeConfig?: boolean;
|
|
44
|
-
status?: boolean;
|
|
45
|
-
yes?: boolean;
|
|
46
|
-
dry?: boolean;
|
|
47
|
-
json?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Maps raw argv flags into {@link ConfigureOpts}. */
|
|
51
|
-
export function parseConfigureOpts(raw: Record<string, string>): ConfigureOpts {
|
|
52
|
-
const flag = (name: string) => raw[name] === "1";
|
|
53
|
-
return {
|
|
54
|
-
refresh: flag("refresh"),
|
|
55
|
-
removeAll: flag("remove-all"),
|
|
56
|
-
removeConfig: flag("remove-config"),
|
|
57
|
-
status: flag("status"),
|
|
58
|
-
yes: flag("yes"),
|
|
59
|
-
dry: flag("dry"),
|
|
60
|
-
json: flag("json"),
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Returns an error message when configure flags are inconsistent; otherwise null. */
|
|
65
|
-
export function validateConfigureOpts(opts: ConfigureOpts): string | null {
|
|
66
|
-
const flags = [opts.refresh, opts.removeAll, opts.removeConfig, opts.status].filter(Boolean);
|
|
67
|
-
if (flags.length > 1) {
|
|
68
|
-
return "Use only one of --refresh, --remove-all, --remove-config, or --status.";
|
|
69
|
-
}
|
|
70
|
-
if (opts.json) {
|
|
71
|
-
opts.yes = true;
|
|
72
|
-
}
|
|
73
|
-
if ((opts.refresh || opts.removeAll || opts.removeConfig) && !opts.yes) {
|
|
74
|
-
return "--yes is required with --refresh, --remove-all, or --remove-config.";
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Adapts configure flags to internal install-plan option shape. */
|
|
80
|
-
function configureToInstallOpts(opts: ConfigureOpts): InstallOpts {
|
|
81
|
-
if (opts.status) {
|
|
82
|
-
return { status: true, yes: opts.yes, dry: opts.dry, json: opts.json };
|
|
83
|
-
}
|
|
84
|
-
if (opts.refresh) {
|
|
85
|
-
return { reinstall: true, yes: true, dry: opts.dry, json: opts.json };
|
|
86
|
-
}
|
|
87
|
-
if (opts.removeAll) {
|
|
88
|
-
return { uninstall: true, all: true, yes: true, dry: opts.dry, json: opts.json };
|
|
89
|
-
}
|
|
90
|
-
if (opts.removeConfig) {
|
|
91
|
-
return { uninstall: true, configure: true, yes: true, dry: opts.dry, json: opts.json };
|
|
92
|
-
}
|
|
93
|
-
return { dry: opts.dry, json: opts.json };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/** Installs the agent skill bundle and returns changed paths. */
|
|
97
|
-
function runSkillAction(root: CliProgram, opts: InstallOpts): string[] {
|
|
98
|
-
return cliSkillInstall(root, {
|
|
99
|
-
global: true,
|
|
100
|
-
rimraf: true,
|
|
101
|
-
dry: opts.dry,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** Tallies configure mutations for the closing summary and `--json` output. */
|
|
106
|
-
export interface ConfigureMutationSummary {
|
|
107
|
-
paths: string[];
|
|
108
|
-
installed: number;
|
|
109
|
-
removed: number;
|
|
110
|
-
configured: number;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function emptyMutationSummary(): ConfigureMutationSummary {
|
|
114
|
-
return { paths: [], installed: 0, removed: 0, configured: 0 };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function mergeMutationSummary(into: ConfigureMutationSummary, from: ConfigureMutationSummary): void {
|
|
118
|
-
into.paths.push(...from.paths);
|
|
119
|
-
into.installed += from.installed;
|
|
120
|
-
into.removed += from.removed;
|
|
121
|
-
into.configured += from.configured;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function recordArtifactMutation(
|
|
125
|
-
summary: ConfigureMutationSummary,
|
|
126
|
-
paths: string[],
|
|
127
|
-
kind: "installed" | "removed" | "configured",
|
|
128
|
-
): void {
|
|
129
|
-
if (paths.length === 0) return;
|
|
130
|
-
summary.paths.push(...paths);
|
|
131
|
-
summary[kind]++;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/** Human-readable closing line for configure mutations. */
|
|
135
|
-
export function formatConfigureMutationSummary(summary: ConfigureMutationSummary, opts: ConfigureOpts): string | null {
|
|
136
|
-
if (summary.paths.length === 0) return null;
|
|
137
|
-
|
|
138
|
-
if (opts.removeAll || opts.removeConfig) {
|
|
139
|
-
const n = summary.removed;
|
|
140
|
-
if (n === 0) return null;
|
|
141
|
-
return n === 1 ? "Removed 1 artifact." : `Removed ${n} artifacts.`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (opts.refresh) {
|
|
145
|
-
const n = summary.installed;
|
|
146
|
-
if (n === 0) return null;
|
|
147
|
-
return n === 1 ? "Refreshed 1 artifact." : `Refreshed ${n} artifacts.`;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const parts: string[] = [];
|
|
151
|
-
if (summary.removed > 0) {
|
|
152
|
-
parts.push(summary.removed === 1 ? "Removed 1 artifact" : `Removed ${summary.removed} artifacts`);
|
|
153
|
-
}
|
|
154
|
-
if (summary.installed > 0) {
|
|
155
|
-
parts.push(summary.installed === 1 ? "Installed 1 artifact" : `Installed ${summary.installed} artifacts`);
|
|
156
|
-
}
|
|
157
|
-
if (summary.configured > 0) {
|
|
158
|
-
parts.push("Updated app config");
|
|
159
|
-
}
|
|
160
|
-
if (parts.length === 0) return null;
|
|
161
|
-
return `${parts.join("; ")}.`;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** Runs one install/uninstall action and returns changed paths. */
|
|
165
|
-
function runPlanAction(
|
|
166
|
-
root: CliProgram,
|
|
167
|
-
action: InstallAction | UninstallAction,
|
|
168
|
-
opts: InstallOpts,
|
|
169
|
-
paths: ReturnType<typeof resolveInstallPaths>,
|
|
170
|
-
): string[] {
|
|
171
|
-
if ("kind" in action && action.kind && isAgentSkillActionKind(action.kind)) {
|
|
172
|
-
const runResult = action.run();
|
|
173
|
-
if (runResult.length > 0) return runResult;
|
|
174
|
-
if (opts.uninstall) {
|
|
175
|
-
const skillDir = skillDirFromUninstallSummary(action.summary, paths);
|
|
176
|
-
return skillDir ? uninstallSkillDir(skillDir, !!opts.dry) : [];
|
|
177
|
-
}
|
|
178
|
-
return runSkillAction(root, opts);
|
|
179
|
-
}
|
|
180
|
-
if (!("kind" in action) || !action.kind) {
|
|
181
|
-
const skillDir = skillDirFromUninstallSummary(action.summary, paths);
|
|
182
|
-
if (skillDir) return uninstallSkillDir(skillDir, !!opts.dry);
|
|
183
|
-
}
|
|
184
|
-
return action.run();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function configureHookContext(root: CliProgram, paths: InstallPaths, dry: boolean): ConfigureHookContext {
|
|
22
|
+
function configureHookContext(root: CliProgram, paths: InstallPaths): ConfigureHookContext {
|
|
188
23
|
return {
|
|
189
24
|
program: root,
|
|
190
|
-
dry,
|
|
25
|
+
dry: false,
|
|
191
26
|
paths: {
|
|
192
27
|
agentsSkillDir: paths.agentsSkillDir,
|
|
193
28
|
agentsMcpPath: paths.agentsMcpPath,
|
|
@@ -201,213 +36,88 @@ async function runConfigureLifecycleHook(
|
|
|
201
36
|
hook: ((ctx: ConfigureHookContext) => void | Promise<void>) | undefined,
|
|
202
37
|
root: CliProgram,
|
|
203
38
|
paths: InstallPaths,
|
|
204
|
-
dry: boolean,
|
|
205
39
|
): Promise<void> {
|
|
206
40
|
if (!hook) return;
|
|
207
|
-
await hook(configureHookContext(root, paths
|
|
41
|
+
await hook(configureHookContext(root, paths));
|
|
208
42
|
}
|
|
209
43
|
|
|
210
|
-
|
|
211
|
-
function executePlan(
|
|
212
|
-
root: CliProgram,
|
|
213
|
-
actions: Array<InstallAction | UninstallAction>,
|
|
214
|
-
opts: InstallOpts,
|
|
215
|
-
showProgress: boolean,
|
|
216
|
-
): ConfigureMutationSummary {
|
|
217
|
-
const summary = emptyMutationSummary();
|
|
218
|
-
const paths = resolveInstallPaths(root);
|
|
44
|
+
function executePlan(actions: Array<InstallAction | UninstallAction>): void {
|
|
219
45
|
for (const action of actions) {
|
|
220
|
-
|
|
221
|
-
installInfo(action.message, opts);
|
|
222
|
-
}
|
|
223
|
-
const changed = runPlanAction(root, action, opts, paths);
|
|
224
|
-
if (changed.length === 0) continue;
|
|
225
|
-
if (action.kind === "agent-skill" && !opts.uninstall && !opts.dry) {
|
|
226
|
-
installOut(`Skill installed to ${displayInstallPath(paths.agentsSkillDir)}/`, opts);
|
|
227
|
-
}
|
|
228
|
-
if (action.kind === "agents-mcp" && !opts.uninstall && !opts.dry) {
|
|
229
|
-
installOut(`MCP server registered in ${displayInstallPath(paths.agentsMcpPath)}`, opts);
|
|
230
|
-
}
|
|
231
|
-
if (action.kind === "configure") {
|
|
232
|
-
recordArtifactMutation(summary, changed, opts.uninstall ? "removed" : "configured");
|
|
233
|
-
} else {
|
|
234
|
-
recordArtifactMutation(summary, changed, opts.uninstall ? "removed" : "installed");
|
|
235
|
-
}
|
|
46
|
+
action.run();
|
|
236
47
|
}
|
|
237
|
-
return summary;
|
|
238
48
|
}
|
|
239
49
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
root: CliProgram,
|
|
243
|
-
paths: ReturnType<typeof resolveInstallPaths>,
|
|
244
|
-
detected: ReturnType<typeof buildDetectedSnapshot>,
|
|
245
|
-
key: CliInstallArtifactKey,
|
|
246
|
-
mode: "install" | "uninstall",
|
|
247
|
-
opts: InstallOpts,
|
|
248
|
-
): TargetPlanContext {
|
|
249
|
-
const effective = resolveEffectiveInstallTargets(root.configure, root);
|
|
250
|
-
const base = buildTargetPlanContext(root, paths, opts, detected);
|
|
251
|
-
return {
|
|
252
|
-
...base,
|
|
253
|
-
mode: mode === "install" ? "install-scoped" : "uninstall-scoped",
|
|
254
|
-
include: (k) => k === key && effective[k].enabled,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
50
|
+
function runInstallWizard(root: CliProgram): void {
|
|
51
|
+
if (!appConfigHasEntries(root)) return;
|
|
257
52
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
root: CliProgram,
|
|
261
|
-
paths: ReturnType<typeof resolveInstallPaths>,
|
|
262
|
-
key: CliInstallArtifactKey,
|
|
263
|
-
action: "install" | "uninstall",
|
|
264
|
-
opts: InstallOpts,
|
|
265
|
-
): Array<InstallAction | UninstallAction> {
|
|
266
|
-
const detected = buildDetectedSnapshot(root, paths);
|
|
267
|
-
const target = installTargetForKey(key);
|
|
268
|
-
if (!target) return [];
|
|
269
|
-
const ctx = buildSingleTargetContext(root, paths, detected, key, action, opts);
|
|
270
|
-
if (action === "install") {
|
|
271
|
-
return target.planInstall(ctx);
|
|
272
|
-
}
|
|
273
|
-
return target.planUninstall(ctx);
|
|
274
|
-
}
|
|
53
|
+
const { resolved } = bootstrapAppConfig(root, { validateFile: false });
|
|
54
|
+
const missing = missingRequiredConfig(root, resolved);
|
|
275
55
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
56
|
+
if (process.stdin.isTTY) {
|
|
57
|
+
if (missing.length === 0) return;
|
|
58
|
+
runConfigure(root, { context: "after-install", showHeading: true, rePromptAll: false });
|
|
59
|
+
return;
|
|
280
60
|
}
|
|
281
61
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const effective = resolveEffectiveInstallTargets(root.configure, root);
|
|
286
|
-
const mutationOpts: InstallOpts = { dry: opts.dry, json: opts.json };
|
|
287
|
-
const summary = emptyMutationSummary();
|
|
288
|
-
|
|
289
|
-
for (const target of INSTALL_TARGETS) {
|
|
290
|
-
if (target.key === "app" || target.key === "skill" || target.key === "agentsMcp") continue;
|
|
291
|
-
if (!effective[target.key].enabled) continue;
|
|
292
|
-
if (target.key !== "configure" && !target.isAvailable(root, paths)) continue;
|
|
293
|
-
if (target.key === "configure" && !root.appConfig) continue;
|
|
294
|
-
|
|
295
|
-
if (target.key === "configure") {
|
|
296
|
-
if (!appConfigHasEntries(root)) continue;
|
|
297
|
-
|
|
298
|
-
const result = runConfigure(root, { context: "standalone", showHeading: false, rePromptAll: true });
|
|
299
|
-
if (result.changed) {
|
|
300
|
-
installOut(`Wrote config: ${displayAppConfigPath(root)}`, mutationOpts);
|
|
301
|
-
recordArtifactMutation(summary, [displayAppConfigPath(root)], "configured");
|
|
302
|
-
}
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const label = artifactPromptLabel(target.key);
|
|
307
|
-
const installed = target.detectedForSnapshot(detected);
|
|
308
|
-
|
|
309
|
-
const statusHint = installed ? "installed" : "not installed";
|
|
310
|
-
process.stderr.write(`\n${label} (${statusHint})\n`);
|
|
311
|
-
const choice = promptTargetAction(label, installed);
|
|
312
|
-
if (!choice || choice === "skip") continue;
|
|
313
|
-
|
|
314
|
-
const actions = actionsForTarget(root, paths, target.key, choice, mutationOpts);
|
|
315
|
-
if (actions.length === 0) continue;
|
|
316
|
-
|
|
317
|
-
const installActions = actions.filter(
|
|
318
|
-
(a): a is InstallAction => "kind" in a && typeof a.kind === "string" && a.kind.includes("-mcp"),
|
|
319
|
-
);
|
|
320
|
-
if (choice === "install" && resolveCapabilities(root).mcp && installActions.length > 0) {
|
|
321
|
-
runTargetPreflight(root, paths, mutationOpts, installActions);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
mergeMutationSummary(
|
|
325
|
-
summary,
|
|
326
|
-
executePlan(root, actions, { ...mutationOpts, uninstall: choice === "uninstall" }, true),
|
|
327
|
-
);
|
|
62
|
+
if (missing.length > 0) {
|
|
63
|
+
installErr(formatMissingConfigMessage(root, missing));
|
|
64
|
+
process.exit(1);
|
|
328
65
|
}
|
|
329
|
-
|
|
330
|
-
return summary;
|
|
331
66
|
}
|
|
332
67
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
printInstallStatus(root, installOpts);
|
|
340
|
-
return emptyMutationSummary();
|
|
68
|
+
function confirmUninstall(root: CliProgram, yes: boolean): void {
|
|
69
|
+
if (yes || !process.stdin.isTTY) return;
|
|
70
|
+
process.stderr.write(`Remove agent artifacts for ${root.key}? [y/N]: `);
|
|
71
|
+
const ans = readPromptLine().trim().toLowerCase();
|
|
72
|
+
if (ans !== "y" && ans !== "yes") {
|
|
73
|
+
process.exit(0);
|
|
341
74
|
}
|
|
75
|
+
}
|
|
342
76
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
77
|
+
/** Installs agent artifacts, bootstraps config, and runs the required-config wizard when needed. */
|
|
78
|
+
export async function cliConfigureInstall(root: CliProgram): Promise<never> {
|
|
79
|
+
const paths = resolveInstallPaths(root);
|
|
80
|
+
const installOpts: InstallOpts = { reinstall: true, all: true };
|
|
348
81
|
|
|
349
|
-
|
|
350
|
-
const bootstrapped = ensureAppConfigFile(root,
|
|
82
|
+
try {
|
|
83
|
+
const bootstrapped = ensureAppConfigFile(root, false);
|
|
351
84
|
if (bootstrapped) {
|
|
352
|
-
|
|
353
|
-
recordArtifactMutation(summary, [display], "configured");
|
|
354
|
-
installOut(`Initialized config: ${display}`, installOpts);
|
|
85
|
+
process.stdout.write(`Initialized config: ${displayAppConfigPath(root)}\n`);
|
|
355
86
|
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
let actions: Array<InstallAction | UninstallAction>;
|
|
359
|
-
if (installOpts.uninstall) {
|
|
360
|
-
actions = buildUninstallPlan(root, paths, installOpts);
|
|
361
|
-
} else if (installOpts.reinstall) {
|
|
362
|
-
actions = buildUpdatePlan(root, paths, installOpts);
|
|
363
|
-
} else {
|
|
364
|
-
actions = buildInstallPlan(root, paths, installOpts);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const installActions = actions.filter(
|
|
368
|
-
(a): a is InstallAction => "kind" in a && typeof a.kind === "string" && a.kind.includes("-mcp"),
|
|
369
|
-
);
|
|
370
|
-
if (!installOpts.uninstall && resolveCapabilities(root).mcp && installActions.length > 0) {
|
|
371
|
-
runTargetPreflight(root, paths, installOpts, installActions);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
mergeMutationSummary(summary, executePlan(root, actions, installOpts, true));
|
|
375
87
|
|
|
376
|
-
|
|
377
|
-
|
|
88
|
+
const actions = buildUpdatePlan(root, paths, installOpts);
|
|
89
|
+
executePlan(actions);
|
|
90
|
+
runInstallWizard(root);
|
|
91
|
+
await runConfigureLifecycleHook(root.configure?.afterInstall, root, paths);
|
|
92
|
+
} catch (err) {
|
|
93
|
+
installErr(err instanceof Error ? err.message : String(err));
|
|
94
|
+
process.exit(1);
|
|
378
95
|
}
|
|
379
96
|
|
|
380
|
-
|
|
97
|
+
process.exit(0);
|
|
381
98
|
}
|
|
382
99
|
|
|
383
|
-
/**
|
|
384
|
-
export async function
|
|
385
|
-
const
|
|
386
|
-
const
|
|
387
|
-
if (err) {
|
|
388
|
-
installErr(err);
|
|
389
|
-
process.exit(1);
|
|
390
|
-
}
|
|
100
|
+
/** Removes agent artifacts and app config. */
|
|
101
|
+
export async function cliConfigureUninstall(root: CliProgram, opts: { yes?: boolean }): Promise<never> {
|
|
102
|
+
const paths = resolveInstallPaths(root);
|
|
103
|
+
const uninstallOpts: InstallOpts = { uninstall: true, all: true };
|
|
391
104
|
|
|
392
|
-
|
|
105
|
+
confirmUninstall(root, !!opts.yes);
|
|
393
106
|
|
|
394
|
-
let summary = emptyMutationSummary();
|
|
395
107
|
try {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
108
|
+
await runConfigureLifecycleHook(root.configure?.beforeUninstall, root, paths);
|
|
109
|
+
const actions = buildUninstallPlan(root, paths, uninstallOpts);
|
|
110
|
+
executePlan(actions);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
installErr(err instanceof Error ? err.message : String(err));
|
|
399
113
|
process.exit(1);
|
|
400
114
|
}
|
|
401
115
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
process.exit(0);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const closing = formatConfigureMutationSummary(summary, opts);
|
|
408
|
-
if (!opts.status && closing) {
|
|
409
|
-
installOut(closing, configureToInstallOpts(opts));
|
|
410
|
-
}
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
411
118
|
|
|
119
|
+
/** Prints install status (human or JSON). */
|
|
120
|
+
export function cliConfigureStatus(root: CliProgram, opts: { json?: boolean }): never {
|
|
121
|
+
printInstallStatus(root, { status: true, json: opts.json });
|
|
412
122
|
process.exit(0);
|
|
413
123
|
}
|
package/src/core/types.ts
CHANGED
|
@@ -406,14 +406,13 @@ export interface CliCompletionConfig {
|
|
|
406
406
|
|
|
407
407
|
/** Opt-in agent skill install to `~/.agents/skills/<key>/` (default: disabled). */
|
|
408
408
|
export interface CliSkillConfig {
|
|
409
|
-
/** When `true`, install
|
|
409
|
+
/** When `true`, install the agent skill via `configure install`. Default false when omitted. */
|
|
410
410
|
enabled?: boolean;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
413
|
/** Context for {@link CliConfigureConfig} lifecycle hooks. */
|
|
414
414
|
export interface ConfigureHookContext {
|
|
415
415
|
program: CliProgram;
|
|
416
|
-
/** When true, the configure run is `--dry` (hook should not write files). */
|
|
417
416
|
dry: boolean;
|
|
418
417
|
paths: {
|
|
419
418
|
agentsSkillDir: string;
|
|
@@ -427,12 +426,12 @@ export interface ConfigureHookContext {
|
|
|
427
426
|
export interface CliConfigureConfig {
|
|
428
427
|
/** When `false`, hide/disable `configure` (default: enabled). */
|
|
429
428
|
enabled?: boolean;
|
|
430
|
-
/** Per-artifact gates for configure
|
|
429
|
+
/** Per-artifact gates for configure install. See {@link resolveEffectiveInstallTargets}. */
|
|
431
430
|
targets?: CliConfigureTargets;
|
|
432
|
-
/** Runs after framework artifacts are installed
|
|
433
|
-
|
|
434
|
-
/** Runs before framework artifacts are removed (`configure
|
|
435
|
-
|
|
431
|
+
/** Runs after framework artifacts are installed (`configure install`). */
|
|
432
|
+
afterInstall?: (ctx: ConfigureHookContext) => void | Promise<void>;
|
|
433
|
+
/** Runs before framework artifacts are removed (`configure uninstall`). */
|
|
434
|
+
beforeUninstall?: (ctx: ConfigureHookContext) => void | Promise<void>;
|
|
436
435
|
}
|
|
437
436
|
|
|
438
437
|
/** Boolean or structured gate for one install artifact. */
|
|
@@ -441,7 +440,7 @@ export type InstallTargetSpec =
|
|
|
441
440
|
| {
|
|
442
441
|
/** When false, artifact is never installed (even with scoped CLI flags). Default true. */
|
|
443
442
|
enabled?: boolean;
|
|
444
|
-
/** When true, included in `configure
|
|
443
|
+
/** When true, included in `configure install`. Default varies by key. */
|
|
445
444
|
includedInAll?: boolean;
|
|
446
445
|
};
|
|
447
446
|
|
package/src/docs/docs.test.ts
CHANGED
|
@@ -153,7 +153,7 @@ test("docs mcp when MCP enabled", async () => {
|
|
|
153
153
|
expect(result.stdout).toContain("MCP server (myapp)");
|
|
154
154
|
expect(result.stdout).toContain("myapp mcp");
|
|
155
155
|
expect(result.stdout).toContain("claude_desktop_config.json");
|
|
156
|
-
expect(result.stdout).toContain("configure
|
|
156
|
+
expect(result.stdout).toContain("configure install");
|
|
157
157
|
});
|
|
158
158
|
|
|
159
159
|
test("docs rejects unknown subcommand", async () => {
|
|
@@ -304,7 +304,7 @@ test("generateMcpGuide includes schema URI and .agents install", () => {
|
|
|
304
304
|
expect(guide).toContain("claude_desktop_config.json");
|
|
305
305
|
expect(guide).toContain("## Installation");
|
|
306
306
|
expect(guide).toContain("## Running directly");
|
|
307
|
-
expect(guide).toContain("configure
|
|
307
|
+
expect(guide).toContain("configure install");
|
|
308
308
|
expect(guide).toContain("dotagentsprotocol.com");
|
|
309
309
|
expect(guide).not.toContain("OpenAI Codex");
|
|
310
310
|
});
|
package/src/docs/mcp-guide.ts
CHANGED
|
@@ -81,7 +81,7 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
81
81
|
"",
|
|
82
82
|
"### `.agents` auto-install",
|
|
83
83
|
"",
|
|
84
|
-
"When `mcpServer.enabled` is set, `configure
|
|
84
|
+
"When `mcpServer.enabled` is set, `configure install` merges this server into `~/.agents/mcp.json` per the https://dotagentsprotocol.com.",
|
|
85
85
|
"",
|
|
86
86
|
];
|
|
87
87
|
|
|
@@ -93,7 +93,7 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
93
93
|
|
|
94
94
|
lines.push(
|
|
95
95
|
"```bash",
|
|
96
|
-
`${root.key} configure
|
|
96
|
+
`${root.key} configure install`,
|
|
97
97
|
"```",
|
|
98
98
|
"",
|
|
99
99
|
"Writes or updates `~/.agents/mcp.json` with a `mcpServers` entry for this app.",
|
package/src/skill/generate.ts
CHANGED
|
@@ -154,7 +154,7 @@ function buildSkillMd(root: CliProgram, dirName: string): string {
|
|
|
154
154
|
"",
|
|
155
155
|
"Install follows the https://dotagentsprotocol.com:",
|
|
156
156
|
"",
|
|
157
|
-
`- Auto-install: \`${root.key} configure
|
|
157
|
+
`- Auto-install: \`${root.key} configure install\` when \`skill.enabled\` → \`~/.agents/skills/${dirName}/\``,
|
|
158
158
|
`- Cursor and most coding agents read \`~/.agents/skills/\` natively`,
|
|
159
159
|
"",
|
|
160
160
|
"**Claude Code (manual):** symlink or copy into Claude's skill directory:",
|
package/src/skill/install.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { CliProgram } from "../core/types.ts";
|
|
4
|
-
import { userHome } from "../paths/host.ts";
|
|
4
|
+
import { displayHomePath, userHome } from "../paths/host.ts";
|
|
5
5
|
import { generateSkillBundle } from "./generate.ts";
|
|
6
6
|
import { applySkillInstallHints } from "./hint.ts";
|
|
7
7
|
import { skillDirName } from "./naming.ts";
|
|
@@ -40,6 +40,7 @@ export function cliSkillInstall(root: CliProgram, opts: SkillInstallOpts): strin
|
|
|
40
40
|
writeFileSync(skillPath, skillMd, "utf8");
|
|
41
41
|
writeFileSync(skillCompatPath, skillMd, "utf8");
|
|
42
42
|
writeFileSync(refPath, referenceMd, "utf8");
|
|
43
|
+
process.stdout.write(`Installed skill to ${displayHomePath(dir)}/\n`);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
changed.push(skillPath, skillCompatPath, refPath);
|