@ekanos/cli 0.10.0 → 0.11.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 (57) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/agents-edit.d.ts +49 -0
  3. package/dist/commands/agents-edit.js +385 -0
  4. package/dist/commands/agents-edit.js.map +1 -0
  5. package/dist/commands/agents.d.ts +24 -1
  6. package/dist/commands/agents.js +117 -8
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/reviewers.d.ts +21 -0
  9. package/dist/commands/reviewers.js +162 -0
  10. package/dist/commands/reviewers.js.map +1 -0
  11. package/dist/commands/runs.d.ts +42 -0
  12. package/dist/commands/runs.js +362 -0
  13. package/dist/commands/runs.js.map +1 -0
  14. package/dist/commands/skills.d.ts +60 -0
  15. package/dist/commands/skills.js +397 -0
  16. package/dist/commands/skills.js.map +1 -0
  17. package/dist/commands/team-agents-agents.d.ts +9 -0
  18. package/dist/commands/team-agents-agents.js +188 -0
  19. package/dist/commands/team-agents-agents.js.map +1 -0
  20. package/dist/commands/team-agents-mcp.d.ts +4 -0
  21. package/dist/commands/team-agents-mcp.js +218 -0
  22. package/dist/commands/team-agents-mcp.js.map +1 -0
  23. package/dist/commands/team-agents-triggers.d.ts +12 -0
  24. package/dist/commands/team-agents-triggers.js +251 -0
  25. package/dist/commands/team-agents-triggers.js.map +1 -0
  26. package/dist/commands/team-agents.d.ts +31 -0
  27. package/dist/commands/team-agents.js +71 -0
  28. package/dist/commands/team-agents.js.map +1 -0
  29. package/dist/commands/teams-onboard.d.ts +51 -0
  30. package/dist/commands/teams-onboard.js +261 -0
  31. package/dist/commands/teams-onboard.js.map +1 -0
  32. package/dist/commands/teams.d.ts +16 -1
  33. package/dist/commands/teams.js +22 -3
  34. package/dist/commands/teams.js.map +1 -1
  35. package/dist/index.js +197 -5
  36. package/dist/index.js.map +1 -1
  37. package/dist/reviewers-api.d.ts +33 -0
  38. package/dist/reviewers-api.js +81 -0
  39. package/dist/reviewers-api.js.map +1 -0
  40. package/dist/runs-api.d.ts +34 -0
  41. package/dist/runs-api.js +112 -0
  42. package/dist/runs-api.js.map +1 -0
  43. package/dist/skills-api.d.ts +28 -0
  44. package/dist/skills-api.js +104 -0
  45. package/dist/skills-api.js.map +1 -0
  46. package/dist/teams-api.d.ts +45 -3
  47. package/dist/teams-api.js +72 -3
  48. package/dist/teams-api.js.map +1 -1
  49. package/package.json +2 -2
  50. package/templates/package.json.tmpl +4 -4
  51. package/templates/skills/build-agent/SKILL.md +90 -8
  52. package/templates/skills/build-agent/references/agent-json.md +78 -2
  53. package/templates/skills/build-agent/references/rollout.md +9 -1
  54. package/templates/skills/build-agent/references/set-up-an-integration.md +2 -1
  55. package/templates/skills/build-agent/references/skills.md +78 -0
  56. package/templates/skills/build-agent/references/triggers.md +25 -5
  57. package/templates/skills/ekanos-platform/SKILL.md +108 -3
@@ -0,0 +1,397 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { SOURCE_SKILL_ENTRY_FILE, SOURCE_SKILL_LIMITS, SourceSkillSlugSchema, } from '@ekanos/integration-schema';
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+ import { refreshStoredSession, requireSession, resolveAuthEnvironment, } from '../auth/session.js';
16
+ import { authRequiredError, notFoundError, usageError, validationError, } from '../errors.js';
17
+ import { classifyPath } from '../safe-fs.js';
18
+ import { listSkills, pushSkill, showSkill, } from '../skills-api.js';
19
+ import { resolveSourceTarget } from '../source-target.js';
20
+ import { pluralize } from '../ui.js';
21
+ export const SKILLS_SUBCOMMANDS = ['list', 'show', 'push', 'pull'];
22
+ /** Where an agent directory keeps the skills it uses: `agents/<key>/skills/<slug>/SKILL.md`. */
23
+ export const AGENT_SKILLS_DIR = 'skills';
24
+ /**
25
+ * `skills` — the Source's skills, held by Ekanos in its skill store. A skill
26
+ * is a folder: `SKILL.md` plus any `references/` and `assets/`. `push`
27
+ * stores it as the skill's next version (created on first push, nothing
28
+ * stored when it is unchanged), live for every team at once — or with
29
+ * `--team`, as that one team's own skill. `pull` writes the folder back.
30
+ */
31
+ export async function runSkills(ctx, args) {
32
+ var _a;
33
+ var _b;
34
+ const subcommand = parseSubcommand(args.subcommand);
35
+ // Read the folder before any network call, so a bad one fails fast.
36
+ const folder = subcommand === 'push'
37
+ ? readSkillFolder(requirePath(args.target), args.dir)
38
+ : null;
39
+ const env = resolveAuthEnvironment(ctx, args.host, args.env, {
40
+ projectDir: args.dir,
41
+ });
42
+ const resolved = await resolveSourceTarget(env, requireSession(env.store, env.host), args);
43
+ const client = new SkillsClient(env, resolved.session);
44
+ const source = resolved.source;
45
+ const team = ((_a = args.team) === null || _a === void 0 ? void 0 : _a.trim()) || undefined;
46
+ switch (subcommand) {
47
+ case 'list': {
48
+ const list = await client.call((token) => listSkills(env.host, token, source, team));
49
+ return ctx.succeed(Object.assign({ host: env.host }, list), listSummary(ctx.ui, list.skills, team !== null && team !== void 0 ? team : list.source.slug));
50
+ }
51
+ case 'show': {
52
+ const slug = requireSlug(args.target, 'show');
53
+ const shown = await client.call((token) => showSkill(env.host, token, source, slug, team));
54
+ return ctx.succeed(Object.assign(Object.assign({ host: env.host }, shown), {
55
+ // The listing, not every byte: `pull` is for contents.
56
+ files: shown.files.map((_a) => {
57
+ var { content: _content } = _a, file = __rest(_a, ["content"]);
58
+ return file;
59
+ }) }), skillDetail(ctx.ui, shown));
60
+ }
61
+ case 'pull': {
62
+ const slug = requireSlug(args.target, 'pull');
63
+ const shown = await client.call((token) => showSkill(env.host, token, source, slug, team));
64
+ const outDir = path.resolve(args.dir, (_b = args.out) !== null && _b !== void 0 ? _b : path.join(AGENT_SKILLS_DIR, slug));
65
+ const written = writeSkillFolder(outDir, shown.files);
66
+ return ctx.succeed({
67
+ host: env.host,
68
+ slug,
69
+ version: shown.skill.version,
70
+ dir: outDir,
71
+ files: written,
72
+ }, ctx.ui.result({
73
+ title: `Pulled ${slug}${shown.skill.version ? ` v${shown.skill.version}` : ''}`,
74
+ rows: [
75
+ ['Into', outDir],
76
+ ['Files', shown.files.map((file) => file.path)],
77
+ ],
78
+ notes: [
79
+ `Edit, then "ekanos skills push ${path.relative(args.dir, outDir) || '.'}${team ? ` --team ${team}` : ''}".`,
80
+ ],
81
+ }));
82
+ }
83
+ case 'push': {
84
+ const result = await pushSkillFolder(client, env.host, {
85
+ source,
86
+ team,
87
+ folder: folder,
88
+ });
89
+ return ctx.succeed(Object.assign({ host: env.host }, result), pushSummary(ctx.ui, result));
90
+ }
91
+ }
92
+ }
93
+ /** Every call refreshes the session once on a 401, then gives up. */
94
+ export class SkillsClient {
95
+ constructor(env, session) {
96
+ this.env = env;
97
+ this.session = session;
98
+ }
99
+ async call(send) {
100
+ let result = await send(this.session.accessToken);
101
+ if (result.status === 'unauthorized') {
102
+ this.session = await refreshStoredSession(this.env, this.session);
103
+ result = await send(this.session.accessToken);
104
+ }
105
+ if (result.status === 'ok')
106
+ return result.data;
107
+ throw authRequiredError(`The session for ${this.env.host} could not authorize the skills call.`, `Run "ekanos login --host ${this.env.host}" and retry.`);
108
+ }
109
+ }
110
+ export function pushSkillFolder(client, host, input) {
111
+ const body = Object.assign(Object.assign({ source: input.source }, (input.team ? { team: input.team } : {})), { slug: input.folder.slug, name: input.folder.name, description: input.folder.description, files: input.folder.files });
112
+ return client.call((token) => pushSkill(host, token, body));
113
+ }
114
+ /** Never sent: VCS and OS litter. */
115
+ const IGNORED = new Set(['.git', '.DS_Store', 'node_modules', 'Thumbs.db']);
116
+ /**
117
+ * Read a skill folder: `SKILL.md` and every other file under it. The slug is
118
+ * the frontmatter `name` when it is slug-shaped (Claude Code's own rule is
119
+ * that it matches the folder), else the folder's name; the description is
120
+ * the frontmatter's, else the first paragraph.
121
+ */
122
+ export function readSkillFolder(target, cwd) {
123
+ var _a, _b;
124
+ var _c;
125
+ const dir = path.resolve(cwd, target);
126
+ const entry = path.join(dir, SOURCE_SKILL_ENTRY_FILE);
127
+ if (classifyPath(dir) !== 'directory' || classifyPath(entry) !== 'file') {
128
+ throw notFoundError(`No ${SOURCE_SKILL_ENTRY_FILE} in ${dir}.`, `A skill is a folder holding ${SOURCE_SKILL_ENTRY_FILE} (plus optional references/ and assets/).`);
129
+ }
130
+ const files = [];
131
+ let total = 0;
132
+ const walk = (current) => {
133
+ for (const name of fs.readdirSync(current).sort()) {
134
+ if (IGNORED.has(name) || name.startsWith('.'))
135
+ continue;
136
+ const full = path.join(current, name);
137
+ const kind = classifyPath(full);
138
+ if (kind === 'directory' && current === dir && name === 'scripts') {
139
+ throw validationError(`${full}: executable skills (scripts/) cannot be pushed from the CLI yet.`, 'They need the in-app review flow. Move what the agent must know into SKILL.md or references/.');
140
+ }
141
+ if (kind === 'directory') {
142
+ walk(full);
143
+ continue;
144
+ }
145
+ if (kind !== 'file')
146
+ continue; // symlinks and devices stay home
147
+ const bytes = fs.readFileSync(full);
148
+ total += bytes.byteLength;
149
+ if (bytes.byteLength > SOURCE_SKILL_LIMITS.fileBytes) {
150
+ throw validationError(`${full} is larger than ${SOURCE_SKILL_LIMITS.fileBytes / 1024} KB.`, 'Skills hold instructions and small references; keep big data elsewhere.');
151
+ }
152
+ files.push(Object.assign({ path: path.relative(dir, full).split(path.sep).join('/') }, encodeBytes(bytes)));
153
+ }
154
+ };
155
+ walk(dir);
156
+ if (files.length > SOURCE_SKILL_LIMITS.files) {
157
+ throw validationError(`${dir} holds ${files.length} files; a skill holds at most ${SOURCE_SKILL_LIMITS.files}.`, 'Trim the folder and push again.');
158
+ }
159
+ if (total > SOURCE_SKILL_LIMITS.totalBytes) {
160
+ throw validationError(`${dir} is larger than ${SOURCE_SKILL_LIMITS.totalBytes / 1024 / 1024} MB.`, 'Trim the folder and push again.');
161
+ }
162
+ const markdown = fs.readFileSync(entry, 'utf8');
163
+ const { fields, body } = splitFrontmatter(markdown);
164
+ const fromName = SourceSkillSlugSchema.safeParse((_c = fields.name) !== null && _c !== void 0 ? _c : '');
165
+ const fromDir = SourceSkillSlugSchema.safeParse(path.basename(dir));
166
+ const slug = fromName.success
167
+ ? fromName.data
168
+ : fromDir.success
169
+ ? fromDir.data
170
+ : null;
171
+ if (!slug) {
172
+ throw validationError(`No usable skill slug for ${dir}.`, 'Name the folder (or the frontmatter "name:") in lowercase-with-hyphens, e.g. "refund-policy".');
173
+ }
174
+ const description = clip(((_a = fields.description) === null || _a === void 0 ? void 0 : _a.trim()) || firstParagraph(body), SOURCE_SKILL_LIMITS.descriptionLength);
175
+ if (!description) {
176
+ throw validationError(`${entry} has no description.`, 'Add "description:" to its frontmatter — it is how an agent decides to load the skill.');
177
+ }
178
+ if (!body.trim()) {
179
+ throw validationError(`${entry} has no instructions after its frontmatter.`, 'The body of SKILL.md is what the agent reads.');
180
+ }
181
+ return {
182
+ dir,
183
+ slug,
184
+ name: clip(((_b = fields.name) === null || _b === void 0 ? void 0 : _b.trim()) || slug, SOURCE_SKILL_LIMITS.nameLength),
185
+ description,
186
+ files,
187
+ };
188
+ }
189
+ /** The skill folders beside an agent: `<agentDir>/skills/<slug>/SKILL.md`. */
190
+ export function findAgentSkillFolders(agentDir) {
191
+ const root = path.join(agentDir, AGENT_SKILLS_DIR);
192
+ if (classifyPath(root) !== 'directory')
193
+ return [];
194
+ return fs
195
+ .readdirSync(root)
196
+ .sort()
197
+ .map((name) => path.join(root, name))
198
+ .filter((dir) => classifyPath(dir) === 'directory' &&
199
+ classifyPath(path.join(dir, SOURCE_SKILL_ENTRY_FILE)) === 'file');
200
+ }
201
+ function writeSkillFolder(outDir, files) {
202
+ const written = [];
203
+ for (const file of files) {
204
+ const target = path.resolve(outDir, ...file.path.split('/'));
205
+ if (!target.startsWith(outDir + path.sep)) {
206
+ throw validationError(`Refusing to write ${file.path} outside ${outDir}.`, 'The host sent a path that leaves the folder.');
207
+ }
208
+ const kind = classifyPath(target);
209
+ if (kind !== 'missing' && kind !== 'file') {
210
+ throw validationError(`Refusing to write through ${target} (${kind}).`, 'Remove it, or pass --out <dir>.');
211
+ }
212
+ fs.mkdirSync(path.dirname(target), { recursive: true });
213
+ fs.writeFileSync(target, Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8'));
214
+ written.push(target);
215
+ }
216
+ return written;
217
+ }
218
+ function encodeBytes(bytes) {
219
+ try {
220
+ return {
221
+ encoding: 'utf8',
222
+ content: new TextDecoder('utf-8', { fatal: true }).decode(bytes),
223
+ };
224
+ }
225
+ catch (_a) {
226
+ return { encoding: 'base64', content: bytes.toString('base64') };
227
+ }
228
+ }
229
+ const FRONTMATTER = /^?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/;
230
+ /** Top-level `key: value` pairs only — `name` and `description` are all that is read. */
231
+ function splitFrontmatter(markdown) {
232
+ const match = markdown.match(FRONTMATTER);
233
+ if (!match)
234
+ return { fields: {}, body: markdown };
235
+ const fields = {};
236
+ const lines = match[1].split(/\r?\n/);
237
+ for (let index = 0; index < lines.length; index += 1) {
238
+ const pair = lines[index].match(/^([A-Za-z0-9_-]+):[ \t]*(.*)$/);
239
+ if (!pair)
240
+ continue;
241
+ let value = pair[2].trim();
242
+ const continued = [];
243
+ while (index + 1 < lines.length && /^[ \t]+\S/.test(lines[index + 1])) {
244
+ continued.push(lines[index + 1].trim());
245
+ index += 1;
246
+ }
247
+ if (/^[>|][+-]?$/.test(value))
248
+ value = '';
249
+ value = [value, ...continued].filter(Boolean).join(' ');
250
+ if (value.length >= 2 &&
251
+ ((value.startsWith('"') && value.endsWith('"')) ||
252
+ (value.startsWith("'") && value.endsWith("'")))) {
253
+ value = value.slice(1, -1);
254
+ }
255
+ fields[pair[1]] = value;
256
+ }
257
+ return { fields, body: markdown.slice(match[0].length) };
258
+ }
259
+ function firstParagraph(body) {
260
+ for (const block of body.split(/\r?\n[ \t]*\r?\n/)) {
261
+ const text = block
262
+ .split(/\r?\n/)
263
+ .map((line) => line.trim())
264
+ .filter((line) => line && !/^(#{1,6}\s|[-*+]\s|\d+\.\s|>|\||```)/.test(line))
265
+ .join(' ');
266
+ if (text)
267
+ return text;
268
+ }
269
+ return '';
270
+ }
271
+ function clip(text, max) {
272
+ return text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text;
273
+ }
274
+ function parseSubcommand(value) {
275
+ const match = SKILLS_SUBCOMMANDS.find((name) => name === value);
276
+ if (match)
277
+ return match;
278
+ throw usageError(value
279
+ ? `Unknown skills subcommand "${value}".`
280
+ : 'skills needs a subcommand.', `Run one of: ${SKILLS_SUBCOMMANDS.map((name) => `ekanos skills ${name}`).join(', ')}.`);
281
+ }
282
+ function requireSlug(value, verb) {
283
+ const parsed = SourceSkillSlugSchema.safeParse(value !== null && value !== void 0 ? value : '');
284
+ if (parsed.success)
285
+ return parsed.data;
286
+ throw usageError(value
287
+ ? `"${value}" is not a skill slug.`
288
+ : `skills ${verb} needs a skill slug.`, `Pass the slug, e.g. "ekanos skills ${verb} refund-policy". "ekanos skills list" shows them.`);
289
+ }
290
+ function requirePath(value) {
291
+ if (value)
292
+ return value;
293
+ throw usageError('skills push needs a skill folder.', `Pass the folder holding ${SOURCE_SKILL_ENTRY_FILE}, e.g. "ekanos skills push agents/support/skills/refund-policy".`);
294
+ }
295
+ const LEVEL_LABEL = {
296
+ platform: 'platform (read-only)',
297
+ source: 'every team',
298
+ team: 'team only',
299
+ };
300
+ function listSummary(ui, skills, where) {
301
+ if (skills.length === 0) {
302
+ return ui.result({
303
+ title: `No skills on ${where} yet`,
304
+ tone: 'warn',
305
+ notes: ['"ekanos skills push <dir>" stores the first one.'],
306
+ });
307
+ }
308
+ return [
309
+ ui.result({
310
+ title: `${pluralize(skills.length, 'skill')} on ${where}`,
311
+ rows: skills.map((skill) => [
312
+ skill.slug,
313
+ [
314
+ skill.name === skill.slug ? null : skill.name,
315
+ LEVEL_LABEL[skill.level],
316
+ skill.version ? `v${skill.version}` : null,
317
+ skill.fileCount > 1 ? pluralize(skill.fileCount, 'file') : null,
318
+ skill.kind === 'executable' ? 'executable' : null,
319
+ ]
320
+ .filter(Boolean)
321
+ .join(' · '),
322
+ ]),
323
+ }),
324
+ ui.hint('"ekanos skills show <slug>" shows one; "pull" writes it out.'),
325
+ ].join('\n\n');
326
+ }
327
+ function skillDetail(ui, shown) {
328
+ const { skill } = shown;
329
+ return ui.result({
330
+ title: `${skill.name} (${skill.slug})`,
331
+ rows: [
332
+ [
333
+ 'Level',
334
+ skill.team ? `team ${skill.team.slug}` : LEVEL_LABEL[skill.level],
335
+ ],
336
+ ['Description', skill.description],
337
+ ['Version', skill.version ? `v${skill.version}` : 'none published'],
338
+ [
339
+ 'Files',
340
+ shown.files.map((file) => `${file.path} (${formatBytes(file.sizeBytes)})`),
341
+ ],
342
+ [
343
+ 'History',
344
+ shown.versions.map((version) => `v${version.version}` +
345
+ (version.publishedAt
346
+ ? ` published ${version.publishedAt.slice(0, 10)}`
347
+ : '')),
348
+ ],
349
+ ],
350
+ });
351
+ }
352
+ const OUTCOME_TITLE = {
353
+ created: 'Created',
354
+ updated: 'Stored a new version of',
355
+ unchanged: 'Unchanged:',
356
+ };
357
+ export function pushSummary(ui, result) {
358
+ const { skill, changes } = result;
359
+ const rows = [
360
+ [
361
+ 'Level',
362
+ skill.team ? `team ${skill.team.slug}` : LEVEL_LABEL[skill.level],
363
+ ],
364
+ ['Version', skill.version ? `v${skill.version}` : 'none'],
365
+ ];
366
+ if (result.outcome === 'created') {
367
+ rows.push(['Files', changes.added]);
368
+ }
369
+ else {
370
+ if (changes.added.length > 0)
371
+ rows.push(['Added', changes.added]);
372
+ if (changes.changed.length > 0)
373
+ rows.push(['Changed', changes.changed]);
374
+ if (changes.removed.length > 0)
375
+ rows.push(['Removed', changes.removed]);
376
+ if (changes.metadata)
377
+ rows.push(['Name/description', 'changed']);
378
+ }
379
+ return ui.result({
380
+ title: `${OUTCOME_TITLE[result.outcome]} ${skill.slug}`,
381
+ tone: result.outcome === 'unchanged' ? 'warn' : 'ok',
382
+ rows,
383
+ notes: result.outcome === 'unchanged'
384
+ ? ['The folder matches the published version; nothing was stored.']
385
+ : skill.level === 'source'
386
+ ? [
387
+ 'Live now: every agent that names this skill reads the new version.',
388
+ ]
389
+ : [],
390
+ });
391
+ }
392
+ function formatBytes(bytes) {
393
+ if (bytes < 1024)
394
+ return `${bytes} B`;
395
+ return `${(bytes / 1024).toFixed(1)} KB`;
396
+ }
397
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/commands/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n SOURCE_SKILL_ENTRY_FILE,\n SOURCE_SKILL_LIMITS,\n type SourceSkillFile,\n type SourceSkillPushRequest,\n type SourceSkillPushResult,\n type SourceSkillShow,\n SourceSkillSlugSchema,\n type SourceSkillSummary,\n} from '@ekanos/integration-schema';\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nimport type { StoredSession } from '../auth/credential-store';\nimport {\n type AuthEnvironment,\n refreshStoredSession,\n requireSession,\n resolveAuthEnvironment,\n} from '../auth/session';\nimport type { CliContext } from '../context';\nimport {\n authRequiredError,\n notFoundError,\n usageError,\n validationError,\n} from '../errors';\nimport type { ExitCode } from '../exit-codes';\nimport { classifyPath } from '../safe-fs';\nimport {\n type SkillsApiResult,\n listSkills,\n pushSkill,\n showSkill,\n} from '../skills-api';\nimport { resolveSourceTarget } from '../source-target';\nimport { type ResultRow, type Ui, pluralize } from '../ui';\n\nexport const SKILLS_SUBCOMMANDS = ['list', 'show', 'push', 'pull'] as const;\n\ntype SkillsSubcommand = (typeof SKILLS_SUBCOMMANDS)[number];\n\n/** Where an agent directory keeps the skills it uses: `agents/<key>/skills/<slug>/SKILL.md`. */\nexport const AGENT_SKILLS_DIR = 'skills';\n\nexport interface SkillsArgs {\n host?: string;\n source?: string;\n subcommand?: string;\n /** A skill slug, or for `push` a skill folder. */\n target?: string;\n /** A team's slug: that team's own skills instead of the Source's. */\n team?: string;\n /** `pull`: where to write the folder (default `skills/<slug>`). */\n out?: string;\n dir: string;\n env: Record<string, string | undefined>;\n}\n\n/**\n * `skills` — the Source's skills, held by Ekanos in its skill store. A skill\n * is a folder: `SKILL.md` plus any `references/` and `assets/`. `push`\n * stores it as the skill's next version (created on first push, nothing\n * stored when it is unchanged), live for every team at once — or with\n * `--team`, as that one team's own skill. `pull` writes the folder back.\n */\nexport async function runSkills(\n ctx: CliContext,\n args: SkillsArgs,\n): Promise<ExitCode> {\n const subcommand = parseSubcommand(args.subcommand);\n\n // Read the folder before any network call, so a bad one fails fast.\n const folder =\n subcommand === 'push'\n ? readSkillFolder(requirePath(args.target), args.dir)\n : null;\n\n const env = resolveAuthEnvironment(ctx, args.host, args.env, {\n projectDir: args.dir,\n });\n const resolved = await resolveSourceTarget(\n env,\n requireSession(env.store, env.host),\n args,\n );\n const client = new SkillsClient(env, resolved.session);\n const source = resolved.source;\n const team = args.team?.trim() || undefined;\n\n switch (subcommand) {\n case 'list': {\n const list = await client.call((token) =>\n listSkills(env.host, token, source, team),\n );\n return ctx.succeed(\n { host: env.host, ...list },\n listSummary(ctx.ui, list.skills, team ?? list.source.slug),\n );\n }\n case 'show': {\n const slug = requireSlug(args.target, 'show');\n const shown = await client.call((token) =>\n showSkill(env.host, token, source, slug, team),\n );\n return ctx.succeed(\n {\n host: env.host,\n ...shown,\n // The listing, not every byte: `pull` is for contents.\n files: shown.files.map(({ content: _content, ...file }) => file),\n },\n skillDetail(ctx.ui, shown),\n );\n }\n case 'pull': {\n const slug = requireSlug(args.target, 'pull');\n const shown = await client.call((token) =>\n showSkill(env.host, token, source, slug, team),\n );\n const outDir = path.resolve(\n args.dir,\n args.out ?? path.join(AGENT_SKILLS_DIR, slug),\n );\n const written = writeSkillFolder(outDir, shown.files);\n return ctx.succeed(\n {\n host: env.host,\n slug,\n version: shown.skill.version,\n dir: outDir,\n files: written,\n },\n ctx.ui.result({\n title: `Pulled ${slug}${shown.skill.version ? ` v${shown.skill.version}` : ''}`,\n rows: [\n ['Into', outDir],\n ['Files', shown.files.map((file) => file.path)],\n ],\n notes: [\n `Edit, then \"ekanos skills push ${path.relative(args.dir, outDir) || '.'}${team ? ` --team ${team}` : ''}\".`,\n ],\n }),\n );\n }\n case 'push': {\n const result = await pushSkillFolder(client, env.host, {\n source,\n team,\n folder: folder!,\n });\n return ctx.succeed(\n { host: env.host, ...result },\n pushSummary(ctx.ui, result),\n );\n }\n }\n}\n\n/** Every call refreshes the session once on a 401, then gives up. */\nexport class SkillsClient {\n constructor(\n private readonly env: AuthEnvironment,\n private session: StoredSession,\n ) {}\n\n async call<T>(\n send: (accessToken: string) => Promise<SkillsApiResult<T>>,\n ): Promise<T> {\n let result = await send(this.session.accessToken);\n if (result.status === 'unauthorized') {\n this.session = await refreshStoredSession(this.env, this.session);\n result = await send(this.session.accessToken);\n }\n if (result.status === 'ok') return result.data;\n throw authRequiredError(\n `The session for ${this.env.host} could not authorize the skills call.`,\n `Run \"ekanos login --host ${this.env.host}\" and retry.`,\n );\n }\n}\n\nexport function pushSkillFolder(\n client: SkillsClient,\n host: string,\n input: { source: string; team?: string; folder: SkillFolder },\n): Promise<SourceSkillPushResult> {\n const body: SourceSkillPushRequest = {\n source: input.source,\n ...(input.team ? { team: input.team } : {}),\n slug: input.folder.slug,\n name: input.folder.name,\n description: input.folder.description,\n files: input.folder.files,\n };\n return client.call((token) => pushSkill(host, token, body));\n}\n\nexport interface SkillFolder {\n dir: string;\n slug: string;\n name: string;\n description: string;\n files: SourceSkillFile[];\n}\n\n/** Never sent: VCS and OS litter. */\nconst IGNORED = new Set(['.git', '.DS_Store', 'node_modules', 'Thumbs.db']);\n\n/**\n * Read a skill folder: `SKILL.md` and every other file under it. The slug is\n * the frontmatter `name` when it is slug-shaped (Claude Code's own rule is\n * that it matches the folder), else the folder's name; the description is\n * the frontmatter's, else the first paragraph.\n */\nexport function readSkillFolder(target: string, cwd: string): SkillFolder {\n const dir = path.resolve(cwd, target);\n const entry = path.join(dir, SOURCE_SKILL_ENTRY_FILE);\n if (classifyPath(dir) !== 'directory' || classifyPath(entry) !== 'file') {\n throw notFoundError(\n `No ${SOURCE_SKILL_ENTRY_FILE} in ${dir}.`,\n `A skill is a folder holding ${SOURCE_SKILL_ENTRY_FILE} (plus optional references/ and assets/).`,\n );\n }\n\n const files: SourceSkillFile[] = [];\n let total = 0;\n const walk = (current: string) => {\n for (const name of fs.readdirSync(current).sort()) {\n if (IGNORED.has(name) || name.startsWith('.')) continue;\n const full = path.join(current, name);\n const kind = classifyPath(full);\n if (kind === 'directory' && current === dir && name === 'scripts') {\n throw validationError(\n `${full}: executable skills (scripts/) cannot be pushed from the CLI yet.`,\n 'They need the in-app review flow. Move what the agent must know into SKILL.md or references/.',\n );\n }\n if (kind === 'directory') {\n walk(full);\n continue;\n }\n if (kind !== 'file') continue; // symlinks and devices stay home\n const bytes = fs.readFileSync(full);\n total += bytes.byteLength;\n if (bytes.byteLength > SOURCE_SKILL_LIMITS.fileBytes) {\n throw validationError(\n `${full} is larger than ${SOURCE_SKILL_LIMITS.fileBytes / 1024} KB.`,\n 'Skills hold instructions and small references; keep big data elsewhere.',\n );\n }\n files.push({\n path: path.relative(dir, full).split(path.sep).join('/'),\n ...encodeBytes(bytes),\n });\n }\n };\n walk(dir);\n\n if (files.length > SOURCE_SKILL_LIMITS.files) {\n throw validationError(\n `${dir} holds ${files.length} files; a skill holds at most ${SOURCE_SKILL_LIMITS.files}.`,\n 'Trim the folder and push again.',\n );\n }\n if (total > SOURCE_SKILL_LIMITS.totalBytes) {\n throw validationError(\n `${dir} is larger than ${SOURCE_SKILL_LIMITS.totalBytes / 1024 / 1024} MB.`,\n 'Trim the folder and push again.',\n );\n }\n\n const markdown = fs.readFileSync(entry, 'utf8');\n const { fields, body } = splitFrontmatter(markdown);\n const fromName = SourceSkillSlugSchema.safeParse(fields.name ?? '');\n const fromDir = SourceSkillSlugSchema.safeParse(path.basename(dir));\n const slug = fromName.success\n ? fromName.data\n : fromDir.success\n ? fromDir.data\n : null;\n if (!slug) {\n throw validationError(\n `No usable skill slug for ${dir}.`,\n 'Name the folder (or the frontmatter \"name:\") in lowercase-with-hyphens, e.g. \"refund-policy\".',\n );\n }\n\n const description = clip(\n fields.description?.trim() || firstParagraph(body),\n SOURCE_SKILL_LIMITS.descriptionLength,\n );\n if (!description) {\n throw validationError(\n `${entry} has no description.`,\n 'Add \"description:\" to its frontmatter — it is how an agent decides to load the skill.',\n );\n }\n if (!body.trim()) {\n throw validationError(\n `${entry} has no instructions after its frontmatter.`,\n 'The body of SKILL.md is what the agent reads.',\n );\n }\n\n return {\n dir,\n slug,\n name: clip(fields.name?.trim() || slug, SOURCE_SKILL_LIMITS.nameLength),\n description,\n files,\n };\n}\n\n/** The skill folders beside an agent: `<agentDir>/skills/<slug>/SKILL.md`. */\nexport function findAgentSkillFolders(agentDir: string): string[] {\n const root = path.join(agentDir, AGENT_SKILLS_DIR);\n if (classifyPath(root) !== 'directory') return [];\n return fs\n .readdirSync(root)\n .sort()\n .map((name) => path.join(root, name))\n .filter(\n (dir) =>\n classifyPath(dir) === 'directory' &&\n classifyPath(path.join(dir, SOURCE_SKILL_ENTRY_FILE)) === 'file',\n );\n}\n\nfunction writeSkillFolder(\n outDir: string,\n files: SourceSkillShow['files'],\n): string[] {\n const written: string[] = [];\n for (const file of files) {\n const target = path.resolve(outDir, ...file.path.split('/'));\n if (!target.startsWith(outDir + path.sep)) {\n throw validationError(\n `Refusing to write ${file.path} outside ${outDir}.`,\n 'The host sent a path that leaves the folder.',\n );\n }\n const kind = classifyPath(target);\n if (kind !== 'missing' && kind !== 'file') {\n throw validationError(\n `Refusing to write through ${target} (${kind}).`,\n 'Remove it, or pass --out <dir>.',\n );\n }\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(\n target,\n Buffer.from(file.content, file.encoding === 'base64' ? 'base64' : 'utf8'),\n );\n written.push(target);\n }\n return written;\n}\n\nfunction encodeBytes(\n bytes: Buffer,\n): Pick<SourceSkillFile, 'encoding' | 'content'> {\n try {\n return {\n encoding: 'utf8',\n content: new TextDecoder('utf-8', { fatal: true }).decode(bytes),\n };\n } catch {\n return { encoding: 'base64', content: bytes.toString('base64') };\n }\n}\n\nconst FRONTMATTER = /^?---[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n---[ \\t]*(?:\\r?\\n|$)/;\n\n/** Top-level `key: value` pairs only — `name` and `description` are all that is read. */\nfunction splitFrontmatter(markdown: string): {\n fields: Record<string, string>;\n body: string;\n} {\n const match = markdown.match(FRONTMATTER);\n if (!match) return { fields: {}, body: markdown };\n const fields: Record<string, string> = {};\n const lines = match[1]!.split(/\\r?\\n/);\n for (let index = 0; index < lines.length; index += 1) {\n const pair = lines[index]!.match(/^([A-Za-z0-9_-]+):[ \\t]*(.*)$/);\n if (!pair) continue;\n let value = pair[2]!.trim();\n const continued: string[] = [];\n while (index + 1 < lines.length && /^[ \\t]+\\S/.test(lines[index + 1]!)) {\n continued.push(lines[index + 1]!.trim());\n index += 1;\n }\n if (/^[>|][+-]?$/.test(value)) value = '';\n value = [value, ...continued].filter(Boolean).join(' ');\n if (\n value.length >= 2 &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n fields[pair[1]!] = value;\n }\n return { fields, body: markdown.slice(match[0].length) };\n}\n\nfunction firstParagraph(body: string): string {\n for (const block of body.split(/\\r?\\n[ \\t]*\\r?\\n/)) {\n const text = block\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(\n (line) => line && !/^(#{1,6}\\s|[-*+]\\s|\\d+\\.\\s|>|\\||```)/.test(line),\n )\n .join(' ');\n if (text) return text;\n }\n return '';\n}\n\nfunction clip(text: string, max: number) {\n return text.length > max ? `${text.slice(0, max - 1).trimEnd()}…` : text;\n}\n\nfunction parseSubcommand(value: string | undefined): SkillsSubcommand {\n const match = SKILLS_SUBCOMMANDS.find((name) => name === value);\n if (match) return match;\n throw usageError(\n value\n ? `Unknown skills subcommand \"${value}\".`\n : 'skills needs a subcommand.',\n `Run one of: ${SKILLS_SUBCOMMANDS.map((name) => `ekanos skills ${name}`).join(', ')}.`,\n );\n}\n\nfunction requireSlug(value: string | undefined, verb: string): string {\n const parsed = SourceSkillSlugSchema.safeParse(value ?? '');\n if (parsed.success) return parsed.data;\n throw usageError(\n value\n ? `\"${value}\" is not a skill slug.`\n : `skills ${verb} needs a skill slug.`,\n `Pass the slug, e.g. \"ekanos skills ${verb} refund-policy\". \"ekanos skills list\" shows them.`,\n );\n}\n\nfunction requirePath(value: string | undefined): string {\n if (value) return value;\n throw usageError(\n 'skills push needs a skill folder.',\n `Pass the folder holding ${SOURCE_SKILL_ENTRY_FILE}, e.g. \"ekanos skills push agents/support/skills/refund-policy\".`,\n );\n}\n\nconst LEVEL_LABEL = {\n platform: 'platform (read-only)',\n source: 'every team',\n team: 'team only',\n} as const;\n\nfunction listSummary(\n ui: Ui,\n skills: SourceSkillSummary[],\n where: string,\n): string {\n if (skills.length === 0) {\n return ui.result({\n title: `No skills on ${where} yet`,\n tone: 'warn',\n notes: ['\"ekanos skills push <dir>\" stores the first one.'],\n });\n }\n return [\n ui.result({\n title: `${pluralize(skills.length, 'skill')} on ${where}`,\n rows: skills.map((skill): ResultRow => [\n skill.slug,\n [\n skill.name === skill.slug ? null : skill.name,\n LEVEL_LABEL[skill.level],\n skill.version ? `v${skill.version}` : null,\n skill.fileCount > 1 ? pluralize(skill.fileCount, 'file') : null,\n skill.kind === 'executable' ? 'executable' : null,\n ]\n .filter(Boolean)\n .join(' · '),\n ]),\n }),\n ui.hint('\"ekanos skills show <slug>\" shows one; \"pull\" writes it out.'),\n ].join('\\n\\n');\n}\n\nfunction skillDetail(ui: Ui, shown: SourceSkillShow): string {\n const { skill } = shown;\n return ui.result({\n title: `${skill.name} (${skill.slug})`,\n rows: [\n [\n 'Level',\n skill.team ? `team ${skill.team.slug}` : LEVEL_LABEL[skill.level],\n ],\n ['Description', skill.description],\n ['Version', skill.version ? `v${skill.version}` : 'none published'],\n [\n 'Files',\n shown.files.map(\n (file) => `${file.path} (${formatBytes(file.sizeBytes)})`,\n ),\n ],\n [\n 'History',\n shown.versions.map(\n (version) =>\n `v${version.version}` +\n (version.publishedAt\n ? ` published ${version.publishedAt.slice(0, 10)}`\n : ''),\n ),\n ],\n ],\n });\n}\n\nconst OUTCOME_TITLE = {\n created: 'Created',\n updated: 'Stored a new version of',\n unchanged: 'Unchanged:',\n} as const;\n\nexport function pushSummary(ui: Ui, result: SourceSkillPushResult): string {\n const { skill, changes } = result;\n const rows: ResultRow[] = [\n [\n 'Level',\n skill.team ? `team ${skill.team.slug}` : LEVEL_LABEL[skill.level],\n ],\n ['Version', skill.version ? `v${skill.version}` : 'none'],\n ];\n if (result.outcome === 'created') {\n rows.push(['Files', changes.added]);\n } else {\n if (changes.added.length > 0) rows.push(['Added', changes.added]);\n if (changes.changed.length > 0) rows.push(['Changed', changes.changed]);\n if (changes.removed.length > 0) rows.push(['Removed', changes.removed]);\n if (changes.metadata) rows.push(['Name/description', 'changed']);\n }\n return ui.result({\n title: `${OUTCOME_TITLE[result.outcome]} ${skill.slug}`,\n tone: result.outcome === 'unchanged' ? 'warn' : 'ok',\n rows,\n notes:\n result.outcome === 'unchanged'\n ? ['The folder matches the published version; nothing was stored.']\n : skill.level === 'source'\n ? [\n 'Live now: every agent that names this skill reads the new version.',\n ]\n : [],\n });\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n return `${(bytes / 1024).toFixed(1)} KB`;\n}\n"]}
@@ -0,0 +1,9 @@
1
+ import type { CliContext } from '../context.js';
2
+ import type { ExitCode } from '../exit-codes.js';
3
+ import { type TeamAgentRun } from './team-agents.js';
4
+ /**
5
+ * `ekanos teams agents list|enable|disable|pin|unpin|policy` — a team's
6
+ * provided agents, turned on, versioned and given an approval policy by the
7
+ * Source admin.
8
+ */
9
+ export declare function runTeamAgentsArea(ctx: CliContext, run: TeamAgentRun): Promise<ExitCode>;