@constraint/cli 0.2.0 → 0.2.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +59 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constraint/cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Install, publish, and report Agent Skills with Constraint",
5
5
  "type": "module",
6
6
  "bin": { "constraint": "bin/constraint.js" },
package/src/cli.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  uploadSkill,
30
30
  } from './skills.js';
31
31
 
32
- const VERSION = '0.2.0';
32
+ const VERSION = '0.2.1';
33
33
 
34
34
  const HELP = `Constraint Skills CLI
35
35
 
@@ -78,6 +78,59 @@ function interactive(out) {
78
78
  return Boolean(process.stdin.isTTY && process.stdout.isTTY && !out.json && !out.quiet);
79
79
  }
80
80
 
81
+ function humanize(value) {
82
+ return String(value || '').replaceAll('_', ' ').replace(/\b\w/g, (letter) => letter.toUpperCase());
83
+ }
84
+
85
+ export function skillListPresentation(items, { installed = false, search = null, scope = 'project' } = {}) {
86
+ if (items.length === 0) {
87
+ if (installed) {
88
+ return {
89
+ title: 'No installed skills',
90
+ message: `Nothing is installed in ${scope} scope yet.\n\nBrowse available skills:\nconstraint skills list`,
91
+ };
92
+ }
93
+ if (search) {
94
+ return {
95
+ title: 'No matching skills',
96
+ message: `Nothing matched “${search}”. Try a broader search.`,
97
+ };
98
+ }
99
+ return {
100
+ title: 'No skills yet',
101
+ message: 'Your organization has not published any skills.\n\nPublish the first one:\nconstraint skills upload <path>',
102
+ };
103
+ }
104
+
105
+ if (installed) {
106
+ return {
107
+ title: `${items.length} installed skill${items.length === 1 ? '' : 's'}`,
108
+ message: items.map((item) => [
109
+ `${item.slug} · v${item.version} · ${item.agent}`,
110
+ `${humanize(item.scope)} · ${humanize(item.mode)} · ${item.path}`,
111
+ ].join('\n')).join('\n\n'),
112
+ };
113
+ }
114
+
115
+ return {
116
+ title: `${items.length} available skill${items.length === 1 ? '' : 's'}`,
117
+ message: items.map((item) => [
118
+ `${item.name} (${item.slug}) · v${item.latest_version} · ${humanize(item.domain)}`,
119
+ item.description,
120
+ ].join('\n')).join('\n\n'),
121
+ };
122
+ }
123
+
124
+ function printSkillList(items, options, out) {
125
+ if (out.json) {
126
+ out.data(items);
127
+ return;
128
+ }
129
+ const presentation = skillListPresentation(items, options);
130
+ if (interactive(out)) note(presentation.message, presentation.title);
131
+ else out.line(`${presentation.title}\n${presentation.message}`);
132
+ }
133
+
81
134
  function takeScope(args) {
82
135
  const project = takeFlag(args, '--project');
83
136
  const global = takeFlag(args, '--global');
@@ -182,12 +235,15 @@ async function listSkills(args, config, out) {
182
235
  if (args.length) throw new Error('skills list does not accept positional arguments');
183
236
  if (installed) {
184
237
  if (search) throw new Error('--search cannot be combined with --installed.');
185
- out.data(await installedSkills({ scope: scopeFlag || 'project', agents }));
238
+ const scope = scopeFlag || 'project';
239
+ const skills = await installedSkills({ scope, agents });
240
+ printSkillList(skills, { installed: true, scope }, out);
186
241
  return;
187
242
  }
188
243
  if (scopeFlag || agents.length) throw new Error('--project, --global, and --agent require --installed.');
189
244
  const query = search ? `?search=${encodeURIComponent(search)}` : '';
190
- out.data(await apiRequest(config, `/skills${query}`));
245
+ const skills = await apiRequest(config, `/skills${query}`);
246
+ printSkillList(skills, { search }, out);
191
247
  }
192
248
 
193
249
  async function inspectSkill(args, config, out) {