@crouton-kit/crouter 0.3.1 → 0.3.3
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.
|
@@ -33,6 +33,7 @@ describe('skill find list params', () => {
|
|
|
33
33
|
includeDisabledFlag,
|
|
34
34
|
{ kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: '' },
|
|
35
35
|
{ kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: '' },
|
|
36
|
+
{ kind: 'flag', name: 'full', type: 'bool', required: false, constraint: '' },
|
|
36
37
|
];
|
|
37
38
|
test('no args: defaults applied', async () => {
|
|
38
39
|
const r = await parseArgv(params, []);
|
|
@@ -71,6 +72,12 @@ describe('skill find list params', () => {
|
|
|
71
72
|
const r = await parseArgv(params, ['--plugin', 'my-plugin']);
|
|
72
73
|
assert.equal(r['plugin'], 'my-plugin');
|
|
73
74
|
});
|
|
75
|
+
test('--full presence = true, absence = false', async () => {
|
|
76
|
+
const present = await parseArgv(params, ['--full']);
|
|
77
|
+
assert.equal(present['full'], true);
|
|
78
|
+
const absent = await parseArgv(params, []);
|
|
79
|
+
assert.equal(absent['full'], false);
|
|
80
|
+
});
|
|
74
81
|
});
|
|
75
82
|
// ---------------------------------------------------------------------------
|
|
76
83
|
// skill find search
|
package/dist/commands/human.js
CHANGED
|
@@ -21,7 +21,7 @@ import { readConfig } from '../core/config.js';
|
|
|
21
21
|
import { mkdirSync, existsSync } from 'node:fs';
|
|
22
22
|
import { join, resolve } from 'node:path';
|
|
23
23
|
import { randomBytes } from 'node:crypto';
|
|
24
|
-
import { ask, launchReview, display, inbox, scanInbox, validateDeck, parseDeck, deckPath, atomicWriteJson, readJson, } from '@crouton-kit/humanloop';
|
|
24
|
+
import { ask, launchReview, display, inbox, scanInbox, validateDeck, approveDeck, notifyDeck, parseDeck, deckPath, atomicWriteJson, readJson, } from '@crouton-kit/humanloop';
|
|
25
25
|
const DECK_SCHEMA_HINT = 'Deck must match the humanloop deck schema: {title?, ' +
|
|
26
26
|
'source?:{sessionName?,askedBy?,blockedSince?}, ' +
|
|
27
27
|
'interactions:[{id,title,subtitle?,(body?|bodyPath?),options:[{id,label,' +
|
|
@@ -146,20 +146,10 @@ const humanApprove = defineLeaf({
|
|
|
146
146
|
const title = input['title'];
|
|
147
147
|
const subtitle = input['subtitle'];
|
|
148
148
|
const body = input['body'];
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
options: [
|
|
154
|
-
{ id: 'yes', label: 'Yes' },
|
|
155
|
-
{ id: 'no', label: 'No' },
|
|
156
|
-
],
|
|
157
|
-
};
|
|
158
|
-
if (subtitle !== undefined)
|
|
159
|
-
interaction['subtitle'] = subtitle;
|
|
160
|
-
if (body !== undefined)
|
|
161
|
-
interaction['body'] = body;
|
|
162
|
-
const deck = validateDeck({ interactions: [interaction] });
|
|
149
|
+
const deck = approveDeck(title, {
|
|
150
|
+
...(subtitle !== undefined ? { subtitle } : {}),
|
|
151
|
+
...(body !== undefined ? { body } : {}),
|
|
152
|
+
});
|
|
163
153
|
const cwd = process.cwd();
|
|
164
154
|
const { jobId } = createJob('human', { cwd });
|
|
165
155
|
const idir = interactionDir(jobId, cwd);
|
|
@@ -250,15 +240,7 @@ const humanNotify = defineLeaf({
|
|
|
250
240
|
run: async (input) => {
|
|
251
241
|
const title = input['title'];
|
|
252
242
|
const body = input['body'];
|
|
253
|
-
const
|
|
254
|
-
id: 'notify',
|
|
255
|
-
title,
|
|
256
|
-
kind: 'notify',
|
|
257
|
-
options: [{ id: 'ack', label: 'OK' }],
|
|
258
|
-
};
|
|
259
|
-
if (body !== undefined)
|
|
260
|
-
interaction['body'] = body;
|
|
261
|
-
const deck = validateDeck({ interactions: [interaction] });
|
|
243
|
+
const deck = notifyDeck(title, body !== undefined ? { body } : {});
|
|
262
244
|
const cwd = process.cwd();
|
|
263
245
|
const id = `nfy-${randomBytes(4).toString('hex')}`;
|
|
264
246
|
const idir = interactionDir(id, cwd);
|
package/dist/commands/skill.js
CHANGED
|
@@ -86,11 +86,13 @@ const findList = defineLeaf({
|
|
|
86
86
|
{ kind: 'flag', name: 'include-disabled', type: 'bool', required: false, constraint: 'When present, includes disabled skills.' },
|
|
87
87
|
{ kind: 'flag', name: 'limit', type: 'int', required: false, default: 50, constraint: 'Max 200.' },
|
|
88
88
|
{ kind: 'flag', name: 'cursor', type: 'string', required: false, constraint: 'Opaque token from next_cursor. Omit on first call.' },
|
|
89
|
+
{ kind: 'flag', name: 'full', type: 'bool', required: false, constraint: 'When present, includes each skill\'s description in items. Off by default to keep enumerations cheap; pair with --plugin or --limit to bound cost.' },
|
|
89
90
|
],
|
|
90
91
|
output: [
|
|
91
|
-
{ name: 'items', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope,
|
|
92
|
+
{ name: 'items', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope, enabled, disabled_in?}. With --full, each item also includes description. Sorted by scope then plugin then name ascending.' },
|
|
92
93
|
{ name: 'next_cursor', type: 'string | null', required: true, constraint: 'null means no more items.' },
|
|
93
94
|
{ name: 'total', type: 'integer | null', required: true, constraint: 'Exact when cheap; null otherwise.' },
|
|
95
|
+
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands for drilling into an item or refining the list.' },
|
|
94
96
|
],
|
|
95
97
|
outputKind: 'object',
|
|
96
98
|
effects: ['None. Read-only.'],
|
|
@@ -102,6 +104,7 @@ const findList = defineLeaf({
|
|
|
102
104
|
const limitRaw = input['limit'];
|
|
103
105
|
const limit = Math.min(Math.max(1, limitRaw), 200);
|
|
104
106
|
const cursor = input['cursor'];
|
|
107
|
+
const full = input['full'];
|
|
105
108
|
const scopes = listScopes(scopeStr);
|
|
106
109
|
const skills = scopes
|
|
107
110
|
.flatMap((s) => listAllSkills(s))
|
|
@@ -137,17 +140,22 @@ const findList = defineLeaf({
|
|
|
137
140
|
total: 'count',
|
|
138
141
|
});
|
|
139
142
|
return {
|
|
140
|
-
items: result.items.map((sk) =>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
items: result.items.map((sk) => {
|
|
144
|
+
const base = {
|
|
145
|
+
name: sk.name,
|
|
146
|
+
plugin: sk.plugin,
|
|
147
|
+
scope: sk.scope,
|
|
148
|
+
enabled: sk.enabled,
|
|
149
|
+
disabled_in: sk.disabledIn !== undefined ? sk.disabledIn : null,
|
|
150
|
+
};
|
|
151
|
+
if (full) {
|
|
152
|
+
base['description'] = sk.frontmatter.description !== undefined ? sk.frontmatter.description : null;
|
|
153
|
+
}
|
|
154
|
+
return base;
|
|
155
|
+
}),
|
|
149
156
|
next_cursor: result.next_cursor,
|
|
150
157
|
total: result.total,
|
|
158
|
+
follow_up: 'Use `crtr skill read show <name>` for the full SKILL.md body. Run `crtr skill find list -h` for filters and verbosity.',
|
|
151
159
|
};
|
|
152
160
|
},
|
|
153
161
|
});
|
|
@@ -165,7 +173,8 @@ const findSearch = defineLeaf({
|
|
|
165
173
|
],
|
|
166
174
|
output: [
|
|
167
175
|
{ name: 'query', type: 'string', required: true, constraint: 'Echo of the input query.' },
|
|
168
|
-
{ name: 'hits', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope,
|
|
176
|
+
{ name: 'hits', type: 'object[]', required: true, constraint: 'Each: {name, plugin, scope, score, description}. Sorted by score descending. description is the frontmatter line — the discriminator for picking which hit to read in full.' },
|
|
177
|
+
{ name: 'follow_up', type: 'string', required: true, constraint: 'Concrete next commands for drilling into a hit or refining the search.' },
|
|
169
178
|
],
|
|
170
179
|
outputKind: 'object',
|
|
171
180
|
effects: ['None. Read-only.'],
|
|
@@ -228,13 +237,10 @@ const findSearch = defineLeaf({
|
|
|
228
237
|
name: h.skill.name,
|
|
229
238
|
plugin: h.skill.plugin,
|
|
230
239
|
scope: h.skill.scope,
|
|
231
|
-
path: h.skill.path,
|
|
232
|
-
description: h.skill.frontmatter.description !== undefined ? h.skill.frontmatter.description : null,
|
|
233
|
-
keywords: h.skill.frontmatter.keywords !== undefined ? h.skill.frontmatter.keywords : null,
|
|
234
|
-
enabled: h.skill.enabled,
|
|
235
240
|
score: h.score,
|
|
236
|
-
|
|
241
|
+
description: h.skill.frontmatter.description !== undefined ? h.skill.frontmatter.description : null,
|
|
237
242
|
})),
|
|
243
|
+
follow_up: 'Use `crtr skill read show <name>` for the full SKILL.md body. Run `crtr skill find search -h` for filters.',
|
|
238
244
|
};
|
|
239
245
|
},
|
|
240
246
|
});
|
|
@@ -675,7 +681,7 @@ export function registerSkill() {
|
|
|
675
681
|
help: {
|
|
676
682
|
name: 'skill',
|
|
677
683
|
summary: 'discover, read, author, and manage skill state',
|
|
678
|
-
model: '
|
|
684
|
+
model: '`find` when you do not yet know which skill applies — it locates candidates by topic, keyword, or body text. `read` when you have a name and need the SKILL.md content or its on-disk location. `author` when you are writing a new skill — it carries the template workflow and the scaffolder. `state` when a skill should be hidden from discovery without being removed. Append `-h` at any branch or leaf for its full schema.',
|
|
679
685
|
dynamicState: buildSkillCatalog,
|
|
680
686
|
children: [
|
|
681
687
|
{ name: 'find', desc: 'list, search, or grep skills', useWhen: 'discovering what skills are available' },
|
package/dist/commands/sys.js
CHANGED
|
@@ -605,7 +605,7 @@ const sysUpdateLeaf = defineLeaf({
|
|
|
605
605
|
const r = selfCheck();
|
|
606
606
|
if (r !== null) {
|
|
607
607
|
updates.push({
|
|
608
|
-
name: '@crouton-kit/
|
|
608
|
+
name: '@crouton-kit/crouter',
|
|
609
609
|
kind: 'self',
|
|
610
610
|
current: r.current,
|
|
611
611
|
latest: r.latest,
|
|
@@ -615,7 +615,7 @@ const sysUpdateLeaf = defineLeaf({
|
|
|
615
615
|
}
|
|
616
616
|
else {
|
|
617
617
|
updates.push({
|
|
618
|
-
name: '@crouton-kit/
|
|
618
|
+
name: '@crouton-kit/crouter',
|
|
619
619
|
kind: 'self',
|
|
620
620
|
current: null,
|
|
621
621
|
latest: null,
|
|
@@ -647,7 +647,7 @@ const sysUpdateLeaf = defineLeaf({
|
|
|
647
647
|
void (async () => {
|
|
648
648
|
try {
|
|
649
649
|
if (resolvedTarget === 'self' || resolvedTarget === 'all') {
|
|
650
|
-
appendEvent(jobId, { level: 'info', event: 'self-update:start', message: 'running npm install -g @crouton-kit/
|
|
650
|
+
appendEvent(jobId, { level: 'info', event: 'self-update:start', message: 'running npm install -g @crouton-kit/crouter@latest' });
|
|
651
651
|
selfUpdate();
|
|
652
652
|
const scopes = ['user'];
|
|
653
653
|
if (projectScopeRoot())
|
package/dist/core/auto-update.js
CHANGED
|
@@ -27,7 +27,7 @@ function withinInterval(lastIso, intervalHours) {
|
|
|
27
27
|
return Date.now() - last < intervalHours * HOUR_MS;
|
|
28
28
|
}
|
|
29
29
|
function spawnDetachedSelfUpdate() {
|
|
30
|
-
const child = spawn('npm', ['i', '-g', '@crouton-kit/
|
|
30
|
+
const child = spawn('npm', ['i', '-g', '@crouton-kit/crouter@latest'], {
|
|
31
31
|
detached: true,
|
|
32
32
|
stdio: 'ignore',
|
|
33
33
|
});
|
|
@@ -73,11 +73,10 @@ export function maybeAutoUpdate(argv) {
|
|
|
73
73
|
spawnDetachedSelfUpdate();
|
|
74
74
|
}
|
|
75
75
|
if (content === 'notify') {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
76
|
+
const stale = contentCheck().filter((e) => !e.up_to_date && !e.unreachable);
|
|
77
|
+
if (stale.length > 0) {
|
|
78
|
+
const list = stale.map((e) => `${e.kind} ${e.name}`).join(', ');
|
|
79
|
+
process.stderr.write(`crtr: updates available for ${list} — run \`crtr sys update\`\n`);
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
else if (content === 'apply') {
|
package/dist/core/self-update.js
CHANGED
|
@@ -21,7 +21,7 @@ export function currentVersion() {
|
|
|
21
21
|
return parsed.version;
|
|
22
22
|
}
|
|
23
23
|
export function selfUpdate() {
|
|
24
|
-
const res = spawnSync('npm', ['i', '-g', '@crouton-kit/
|
|
24
|
+
const res = spawnSync('npm', ['i', '-g', '@crouton-kit/crouter@latest'], { stdio: 'inherit' });
|
|
25
25
|
if (res.status !== 0) {
|
|
26
26
|
throw general('npm install failed');
|
|
27
27
|
}
|
|
@@ -29,7 +29,7 @@ export function selfUpdate() {
|
|
|
29
29
|
/** Check whether a newer crtr version is available on npm.
|
|
30
30
|
* Warns to stderr if network unavailable; returns {current, latest} or null if unreachable. */
|
|
31
31
|
export function selfCheck() {
|
|
32
|
-
const res = spawnSync('npm', ['view', '@crouton-kit/
|
|
32
|
+
const res = spawnSync('npm', ['view', '@crouton-kit/crouter', 'version'], { encoding: 'utf8' });
|
|
33
33
|
if (res.status !== 0) {
|
|
34
34
|
return null;
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crouton-kit/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "crtr — fast access to skills, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"license": "MIT",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@crouton-kit/humanloop": "^0.3.
|
|
38
|
+
"@crouton-kit/humanloop": "^0.3.8",
|
|
39
39
|
"commander": "^13.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|