@constraint/cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/package.json +16 -5
- package/src/cli.js +73 -6
- package/src/skills.js +4 -8
package/README.md
CHANGED
|
@@ -129,13 +129,14 @@ constraint skills update --all --global
|
|
|
129
129
|
Create or edit a standard Agent Skill folder locally, then upload it:
|
|
130
130
|
|
|
131
131
|
```bash
|
|
132
|
-
constraint skills upload ./account-research
|
|
132
|
+
constraint skills upload ./account-research --domain sales_pipeline
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
The folder must contain a root `SKILL.md` with `name` and `description` YAML
|
|
136
|
-
frontmatter.
|
|
137
|
-
asks which domain owns the skill.
|
|
138
|
-
changed content creates the next
|
|
136
|
+
frontmatter. Pass the owning domain with `--domain`; if it is omitted in an
|
|
137
|
+
interactive terminal, the CLI asks which permitted domain owns the skill.
|
|
138
|
+
Skill versions are immutable; uploading changed content creates the next
|
|
139
|
+
version.
|
|
139
140
|
|
|
140
141
|
## Report skill runs
|
|
141
142
|
|
package/package.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constraint/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Install, publish, and report Agent Skills with Constraint",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
|
|
6
|
+
"bin": {
|
|
7
|
+
"constraint": "bin/constraint.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src",
|
|
12
|
+
"skills"
|
|
13
|
+
],
|
|
8
14
|
"scripts": {
|
|
9
15
|
"check": "node --check bin/constraint.js && node --check src/cli.js",
|
|
10
16
|
"test": "node --test"
|
|
@@ -13,7 +19,12 @@
|
|
|
13
19
|
"@clack/prompts": "1.7.0",
|
|
14
20
|
"picocolors": "1.1.1"
|
|
15
21
|
},
|
|
16
|
-
"engines": {
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20"
|
|
24
|
+
},
|
|
17
25
|
"license": "SEE LICENSE IN LICENSE",
|
|
18
|
-
"publishConfig": {
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"provenance": true
|
|
29
|
+
}
|
|
19
30
|
}
|
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.
|
|
32
|
+
const VERSION = '0.2.2';
|
|
33
33
|
|
|
34
34
|
const HELP = `Constraint Skills CLI
|
|
35
35
|
|
|
@@ -45,7 +45,7 @@ Usage:
|
|
|
45
45
|
constraint skills update <skill> [--agent <agent>]... [--project|--global]
|
|
46
46
|
[--copy] [--yes]
|
|
47
47
|
constraint skills update --all [--agent <agent>]... [--project|--global] [--yes]
|
|
48
|
-
constraint skills upload <path>
|
|
48
|
+
constraint skills upload <path> --domain <domain>
|
|
49
49
|
constraint skills run start <skill> --client <client> --session <session-id>
|
|
50
50
|
constraint skills run complete <run-id> <transcript-path>
|
|
51
51
|
constraint skills run list [--team <team>]... [--user <user>]... [--skill <skill>]...
|
|
@@ -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');
|
|
@@ -111,6 +164,15 @@ async function chooseDomain(domains) {
|
|
|
111
164
|
return selected;
|
|
112
165
|
}
|
|
113
166
|
|
|
167
|
+
export function resolveUploadDomain(value, domains) {
|
|
168
|
+
if (!value) return null;
|
|
169
|
+
const normalized = String(value).trim().toLowerCase().replaceAll('-', '_').replaceAll(' ', '_');
|
|
170
|
+
if (!domains.includes(normalized)) {
|
|
171
|
+
throw new Error(`You do not have permission to upload skills to ${normalized}. Available domains: ${domains.join(', ') || 'none'}.`);
|
|
172
|
+
}
|
|
173
|
+
return normalized;
|
|
174
|
+
}
|
|
175
|
+
|
|
114
176
|
async function authCommand(command, args, config, out) {
|
|
115
177
|
rejectUnknown(args);
|
|
116
178
|
if (args.length) throw new Error(`${command} does not accept positional arguments`);
|
|
@@ -182,12 +244,15 @@ async function listSkills(args, config, out) {
|
|
|
182
244
|
if (args.length) throw new Error('skills list does not accept positional arguments');
|
|
183
245
|
if (installed) {
|
|
184
246
|
if (search) throw new Error('--search cannot be combined with --installed.');
|
|
185
|
-
|
|
247
|
+
const scope = scopeFlag || 'project';
|
|
248
|
+
const skills = await installedSkills({ scope, agents });
|
|
249
|
+
printSkillList(skills, { installed: true, scope }, out);
|
|
186
250
|
return;
|
|
187
251
|
}
|
|
188
252
|
if (scopeFlag || agents.length) throw new Error('--project, --global, and --agent require --installed.');
|
|
189
253
|
const query = search ? `?search=${encodeURIComponent(search)}` : '';
|
|
190
|
-
|
|
254
|
+
const skills = await apiRequest(config, `/skills${query}`);
|
|
255
|
+
printSkillList(skills, { search }, out);
|
|
191
256
|
}
|
|
192
257
|
|
|
193
258
|
async function inspectSkill(args, config, out) {
|
|
@@ -295,9 +360,11 @@ async function updateCommand(args, config, out) {
|
|
|
295
360
|
}
|
|
296
361
|
|
|
297
362
|
async function uploadCommand(args, config, out) {
|
|
363
|
+
const requestedDomain = takeOption(args, '--domain');
|
|
298
364
|
rejectUnknown(args);
|
|
299
|
-
if (args.length !== 1) throw new Error('Usage: constraint skills upload <path>');
|
|
300
|
-
const
|
|
365
|
+
if (args.length !== 1) throw new Error('Usage: constraint skills upload <path> --domain <domain>');
|
|
366
|
+
const domains = await manageableDomains(config);
|
|
367
|
+
const domain = resolveUploadDomain(requestedDomain, domains) || await chooseDomain(domains);
|
|
301
368
|
const detail = await uploadSkill(config, args[0], domain);
|
|
302
369
|
out.data({ skill_id: detail.skill_id, slug: detail.slug, domain: detail.domain, version: detail.version.version });
|
|
303
370
|
}
|
package/src/skills.js
CHANGED
|
@@ -24,11 +24,6 @@ import {
|
|
|
24
24
|
workspaceId,
|
|
25
25
|
} from './paths.js';
|
|
26
26
|
|
|
27
|
-
export const DOMAINS = [
|
|
28
|
-
'sales_pipeline', 'content_audience', 'marketing_demand', 'offers_monetization',
|
|
29
|
-
'operations_team', 'partnerships_bd',
|
|
30
|
-
];
|
|
31
|
-
|
|
32
27
|
function filesFromDetail(detail) {
|
|
33
28
|
return detail.version.files.map((file) => ({
|
|
34
29
|
path: file.path,
|
|
@@ -71,9 +66,10 @@ export async function uploadSkill(config, localPath, domain) {
|
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
export async function manageableDomains(config) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
const domains = await apiRequest(config, '/domains');
|
|
70
|
+
return domains
|
|
71
|
+
.filter((domain) => domain.permissions.includes('domain:skill_manage'))
|
|
72
|
+
.map((domain) => domain.slug);
|
|
77
73
|
}
|
|
78
74
|
|
|
79
75
|
export async function configuredAgents() {
|