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.
Files changed (48) hide show
  1. package/CHANGELOG.md +17 -3
  2. package/README.md +2 -2
  3. package/docs/README.md +2 -2
  4. package/docs/ai-skills.md +7 -7
  5. package/docs/bundled-docs.md +2 -2
  6. package/docs/cli-program.md +4 -4
  7. package/docs/configure.md +57 -85
  8. package/docs/developing.md +3 -3
  9. package/docs/distribution-homebrew.md +22 -23
  10. package/docs/mcp.md +3 -3
  11. package/examples/full-example/Formula/full-example.rb +7 -9
  12. package/examples/full-example/docs/cli-schema.json +48 -60
  13. package/examples/full-example/docs/cli.md +66 -36
  14. package/examples/full-example/docs/mcp.md +2 -2
  15. package/examples/full-example/docs/skill.md +1 -1
  16. package/examples/full-example/justfile +12 -12
  17. package/examples/full-example/scripts/formula-shared.ts +7 -13
  18. package/examples/full-example-json/Formula/full-example-json.rb +7 -9
  19. package/examples/full-example-json/docs/cli-schema.json +216 -270
  20. package/examples/full-example-json/docs/cli.md +297 -162
  21. package/examples/full-example-json/docs/mcp.md +2 -2
  22. package/examples/full-example-json/docs/skill.md +1 -1
  23. package/examples/full-example-json/justfile +12 -13
  24. package/examples/full-example-json/scripts/formula-shared.ts +7 -13
  25. package/index.d.ts +7 -8
  26. package/package.json +1 -1
  27. package/src/builtins/builtins.test.ts +21 -28
  28. package/src/builtins/configure-copy.ts +17 -20
  29. package/src/builtins/configure.ts +45 -74
  30. package/src/builtins/dispatch.ts +1 -8
  31. package/src/builtins/index.ts +1 -1
  32. package/src/cli-tool/create.ts +3 -1
  33. package/src/cli-tool/post-create.ts +5 -1
  34. package/src/config/file.ts +1 -0
  35. package/src/config/resolve.ts +1 -1
  36. package/src/configure/artifacts/mcp-config.ts +18 -12
  37. package/src/configure/artifacts/target-mcp-json.ts +19 -18
  38. package/src/configure/artifacts/target-skill.ts +8 -3
  39. package/src/configure/artifacts/targets/agents-mcp.ts +1 -1
  40. package/src/configure/artifacts/targets/configure.ts +2 -3
  41. package/src/configure/artifacts/uninstall.ts +5 -1
  42. package/src/configure/configure.test.ts +45 -113
  43. package/src/configure/index.ts +64 -354
  44. package/src/core/types.ts +7 -8
  45. package/src/docs/docs.test.ts +2 -2
  46. package/src/docs/mcp-guide.ts +2 -2
  47. package/src/skill/generate.ts +1 -1
  48. package/src/skill/install.ts +2 -1
@@ -1,193 +1,28 @@
1
1
  /*
2
- Interactive and automated `configure` command orchestration (agent artifacts and app config).
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 { resolveCapabilities } from "../runtime/capabilities.ts";
9
- import { cliSkillInstall, isAgentSkillActionKind } from "../skill/install.ts";
10
- import { displayInstallPath, type InstallPaths, resolveInstallPaths } from "./artifacts/paths.ts";
11
- import { buildInstallPlan, buildUpdatePlan } from "./artifacts/plan.ts";
12
- import {
13
- installErr,
14
- installInfo,
15
- installOut,
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
- /** Parsed flags for the top-level `configure` built-in. */
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, dry));
41
+ await hook(configureHookContext(root, paths));
208
42
  }
209
43
 
210
- /** Runs install or uninstall actions and collects changed paths. */
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
- if (showProgress) {
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
- /** Builds plan context limited to a single artifact key. */
241
- function buildSingleTargetContext(
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
- /** Resolves install or uninstall actions for one artifact target. */
259
- function actionsForTarget(
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
- /** Walks enabled targets with per-target prompts (TTY required). */
277
- async function runInteractiveConfigure(root: CliProgram, opts: ConfigureOpts): Promise<ConfigureMutationSummary> {
278
- if (!process.stdin.isTTY) {
279
- throw new Error("Interactive configure requires a TTY. Use flags such as --refresh --yes.");
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
- writeInteractiveInstallIntro(root);
283
- const paths = resolveInstallPaths(root);
284
- const detected = buildDetectedSnapshot(root, paths);
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
- /** Runs sync, remove, or status modes without per-target prompts. */
334
- async function runAutomatedConfigure(root: CliProgram, opts: ConfigureOpts): Promise<ConfigureMutationSummary> {
335
- const installOpts = configureToInstallOpts(opts);
336
- const paths = resolveInstallPaths(root);
337
-
338
- if (installOpts.status) {
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
- const summary = emptyMutationSummary();
344
-
345
- if (opts.removeAll) {
346
- await runConfigureLifecycleHook(root.configure?.beforeRemoveAll, root, paths, !!installOpts.dry);
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
- if (installOpts.reinstall && !installOpts.uninstall) {
350
- const bootstrapped = ensureAppConfigFile(root, !!installOpts.dry);
82
+ try {
83
+ const bootstrapped = ensureAppConfigFile(root, false);
351
84
  if (bootstrapped) {
352
- const display = displayAppConfigPath(root);
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
- if (opts.refresh) {
377
- await runConfigureLifecycleHook(root.configure?.afterRefresh, root, paths, !!installOpts.dry);
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
- return summary;
97
+ process.exit(0);
381
98
  }
382
99
 
383
- /** Main configure command orchestrator. */
384
- export async function cliConfigure(root: CliProgram, rawOpts: Record<string, string>): Promise<never> {
385
- const opts = parseConfigureOpts(rawOpts);
386
- const err = validateConfigureOpts(opts);
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
- const isInteractive = !opts.refresh && !opts.removeAll && !opts.removeConfig && !opts.status;
105
+ confirmUninstall(root, !!opts.yes);
393
106
 
394
- let summary = emptyMutationSummary();
395
107
  try {
396
- summary = isInteractive ? await runInteractiveConfigure(root, opts) : await runAutomatedConfigure(root, opts);
397
- } catch (mutationErr) {
398
- installErr(mutationErr instanceof Error ? mutationErr.message : String(mutationErr));
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
- if (opts.json && !opts.status) {
403
- process.stdout.write(`${JSON.stringify(summary.paths, null, 2)}\n`);
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 and refresh the agent skill via `configure --refresh`. Default false when omitted. */
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 refresh and interactive wizard. See {@link resolveEffectiveInstallTargets}. */
429
+ /** Per-artifact gates for configure install. See {@link resolveEffectiveInstallTargets}. */
431
430
  targets?: CliConfigureTargets;
432
- /** Runs after framework artifacts are installed/refreshed (`configure --refresh`). */
433
- afterRefresh?: (ctx: ConfigureHookContext) => void | Promise<void>;
434
- /** Runs before framework artifacts are removed (`configure --remove-all`). */
435
- beforeRemoveAll?: (ctx: ConfigureHookContext) => void | Promise<void>;
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 --refresh`. Default varies by key. */
443
+ /** When true, included in `configure install`. Default varies by key. */
445
444
  includedInAll?: boolean;
446
445
  };
447
446
 
@@ -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 --refresh --yes");
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 --refresh");
307
+ expect(guide).toContain("configure install");
308
308
  expect(guide).toContain("dotagentsprotocol.com");
309
309
  expect(guide).not.toContain("OpenAI Codex");
310
310
  });
@@ -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 --refresh` merges this server into `~/.agents/mcp.json` per the https://dotagentsprotocol.com.",
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 --refresh --yes`,
96
+ `${root.key} configure install`,
97
97
  "```",
98
98
  "",
99
99
  "Writes or updates `~/.agents/mcp.json` with a `mcpServers` entry for this app.",
@@ -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 --refresh --yes\` when \`skill.enabled\` → \`~/.agents/skills/${dirName}/\``,
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:",
@@ -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);