@ghostpaw/questlog 0.9.2 → 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.
- package/README.md +144 -4
- package/SKILL.md +95 -40
- package/dist/chunk-7KTRNXTU.js +21 -0
- package/dist/chunk-D6EGZCT7.js +23 -0
- package/dist/chunk-GVD6A3RR.js +108 -0
- package/dist/{chunk-6KTQK3ZE.js → chunk-I2AMIXGP.js} +8 -0
- package/dist/{chunk-3B6FMHZU.js → chunk-IA2GVCZS.js} +35 -2
- package/dist/{chunk-DKH623HU.js → chunk-IL2QRKZL.js} +1 -4
- package/dist/{chunk-UTUQPSGO.js → chunk-KOWIVBG6.js} +68 -588
- package/dist/chunk-NBCCA6AX.js +31 -0
- package/dist/chunk-QK3H2AL5.js +36 -0
- package/dist/chunk-RBGQK5WP.js +949 -0
- package/dist/cli.js +1 -1
- package/dist/{cli_main-XNZP4TY2.js → cli_main-TEG3QTDP.js} +147 -128
- package/dist/index.cjs +1152 -627
- package/dist/index.d.cts +142 -11
- package/dist/index.d.ts +142 -11
- package/dist/index.js +1152 -628
- package/dist/list_deliveries-WJEJUZIQ.js +2 -0
- package/dist/list_hooks-C5CAA2C7.js +2 -0
- package/dist/mcp-server.js +840 -389
- package/dist/mcp.cjs +709 -322
- package/dist/mcp.js +711 -324
- package/dist/open_questlog_db-6NS6BVBC.js +2 -0
- package/dist/{questlog_skill_spec-EM6DGGVN.js → questlog_skill_spec-ILTCTRYS.js} +16 -8
- package/dist/run_hook_command-BOENYNDT.js +155 -0
- package/dist/{serve_questlog_mcp-KFUYJB2P.js → serve_questlog_mcp-X524X34F.js} +6 -3
- package/dist/{skill_markdown-HXYQ3K6U.js → skill_markdown-EGKYZ3W2.js} +4 -20
- package/dist/text_output-X7F3K23Q.js +2 -0
- package/package.json +1 -1
- package/skills/questlog/SKILL.md +95 -40
- package/skills/questlog/references/webhooks.md +94 -0
- package/dist/open_questlog_db-SH3DAU4C.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { questlogSkills } from './chunk-I2AMIXGP.js';
|
|
3
|
+
import { CliUsageError, renderCliHelp, parseCliArgs } from './chunk-GVD6A3RR.js';
|
|
4
|
+
import { isErrorResult, resolveQuestlogDbPath } from './chunk-IL2QRKZL.js';
|
|
5
|
+
import { reviewQuestlogTool, validateInput, getQuestDetail, questlogSurfaceTools } from './chunk-KOWIVBG6.js';
|
|
6
|
+
import { questlogVersion } from './chunk-RBGQK5WP.js';
|
|
7
|
+
import { listDeliveries } from './chunk-D6EGZCT7.js';
|
|
8
|
+
import './chunk-NBCCA6AX.js';
|
|
9
|
+
import { schemaRows } from './chunk-7KTRNXTU.js';
|
|
5
10
|
import { minimalInput } from './chunk-QYSIJ2YN.js';
|
|
6
11
|
import { isSea } from 'node:sea';
|
|
7
|
-
import {
|
|
12
|
+
import { existsSync } from 'node:fs';
|
|
8
13
|
import { resolve } from 'node:path';
|
|
9
14
|
|
|
10
15
|
var npmEntry = false;
|
|
@@ -15,7 +20,8 @@ function cliVersion(version, {
|
|
|
15
20
|
sea = isSea,
|
|
16
21
|
npm = npmEntry,
|
|
17
22
|
platform = process.platform,
|
|
18
|
-
arch = process.arch
|
|
23
|
+
arch = process.arch,
|
|
24
|
+
args = []
|
|
19
25
|
} = {}) {
|
|
20
26
|
let binary = false;
|
|
21
27
|
try {
|
|
@@ -23,116 +29,17 @@ function cliVersion(version, {
|
|
|
23
29
|
} catch {
|
|
24
30
|
}
|
|
25
31
|
const target = `${platform === "win32" ? "windows" : platform}-${arch}`;
|
|
32
|
+
const variant = binary ? "binary" : npm ? "npm" : "library";
|
|
33
|
+
if (args.includes("--json"))
|
|
34
|
+
return JSON.stringify({ name: "questlog", version, variant, target });
|
|
35
|
+
if (args.includes("--short")) return version;
|
|
26
36
|
return `questlog ${version} (${binary ? `binary, ${target}` : npm ? "npm" : "library"})`;
|
|
27
37
|
}
|
|
28
|
-
var CliUsageError = class extends Error {
|
|
29
|
-
exitCode = 2;
|
|
30
|
-
};
|
|
31
|
-
var keyOf = (name) => name.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
32
|
-
function parseCliArgs(argv, spec) {
|
|
33
|
-
const values = {};
|
|
34
|
-
const positions = [];
|
|
35
|
-
const flags = spec.flags ?? [];
|
|
36
|
-
const convert = (raw, arg) => {
|
|
37
|
-
let value = raw;
|
|
38
|
-
if (raw.startsWith("@")) {
|
|
39
|
-
try {
|
|
40
|
-
value = readFileSync(raw.slice(1), "utf8");
|
|
41
|
-
} catch {
|
|
42
|
-
throw new CliUsageError(`Cannot read value file: ${raw.slice(1)}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
let result = value;
|
|
46
|
-
if (arg.type === "number" || arg.type === "integer") {
|
|
47
|
-
result = Number(value);
|
|
48
|
-
if (!value.trim() || !Number.isFinite(result) || arg.type === "integer" && !Number.isInteger(result))
|
|
49
|
-
throw new CliUsageError(`Expected ${arg.type} for ${arg.name}: ${value}`);
|
|
50
|
-
} else if (arg.type === "boolean") {
|
|
51
|
-
if (!["true", "false"].includes(value))
|
|
52
|
-
throw new CliUsageError(`Expected boolean for ${arg.name}`);
|
|
53
|
-
result = value === "true";
|
|
54
|
-
} else if (arg.type === "json") {
|
|
55
|
-
try {
|
|
56
|
-
result = JSON.parse(value);
|
|
57
|
-
} catch {
|
|
58
|
-
throw new CliUsageError(`Invalid JSON for ${arg.name}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (arg.enum && !arg.enum.includes(result))
|
|
62
|
-
throw new CliUsageError(`${arg.name} must be one of: ${arg.enum.join(", ")}`);
|
|
63
|
-
return result;
|
|
64
|
-
};
|
|
65
|
-
let ended = false;
|
|
66
|
-
for (let i = 0; i < argv.length; i++) {
|
|
67
|
-
const token = argv[i];
|
|
68
|
-
if (!ended && token === "--") {
|
|
69
|
-
ended = true;
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
if (ended || token === "-" || !token.startsWith("-")) {
|
|
73
|
-
positions.push(token);
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const [flag, inline] = token.split(/=(.*)/s);
|
|
77
|
-
const negative = flag?.startsWith("--no-");
|
|
78
|
-
const name = flag?.replace(/^--?/, "").replace(/^no-/, "");
|
|
79
|
-
const arg = flags.find(
|
|
80
|
-
(entry) => entry.name === name || keyOf(entry.name) === name || entry.short === name
|
|
81
|
-
);
|
|
82
|
-
if (!arg) {
|
|
83
|
-
const prefix = (name ?? "").slice(0, 3);
|
|
84
|
-
const suggestion = prefix ? flags.find((entry) => entry.name.startsWith(prefix)) : void 0;
|
|
85
|
-
throw new CliUsageError(
|
|
86
|
-
`Unknown flag: ${flag}${suggestion ? `; did you mean --${suggestion.name}?` : ""}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
if (negative && arg.type !== "boolean")
|
|
90
|
-
throw new CliUsageError(`--no-${arg.name} requires a boolean flag`);
|
|
91
|
-
let raw = inline;
|
|
92
|
-
if (arg.type === "boolean" && raw === void 0) raw = negative ? "false" : "true";
|
|
93
|
-
if (raw === void 0) {
|
|
94
|
-
const next = argv[i + 1];
|
|
95
|
-
if (next === void 0 || /^--[a-z]/i.test(next))
|
|
96
|
-
throw new CliUsageError(`Missing value: --${arg.name}`);
|
|
97
|
-
raw = next;
|
|
98
|
-
i++;
|
|
99
|
-
}
|
|
100
|
-
const key = keyOf(arg.name);
|
|
101
|
-
if (arg.type === "array") {
|
|
102
|
-
const item = convert(raw, { ...arg, type: arg.itemType ?? "string" });
|
|
103
|
-
values[key] = [...values[key] ?? [], item];
|
|
104
|
-
} else values[key] = convert(raw, arg);
|
|
105
|
-
}
|
|
106
|
-
let index = 0;
|
|
107
|
-
for (const arg of spec.positionals ?? []) {
|
|
108
|
-
if (index >= positions.length) continue;
|
|
109
|
-
values[keyOf(arg.name)] = arg.variadic ? positions.slice(index).map((value) => convert(value, { ...arg, type: arg.itemType ?? arg.type })) : convert(positions[index], arg);
|
|
110
|
-
index = arg.variadic ? positions.length : index + 1;
|
|
111
|
-
}
|
|
112
|
-
if (index < positions.length)
|
|
113
|
-
throw new CliUsageError(`Unexpected positional: ${positions[index]}`);
|
|
114
|
-
for (const arg of [...flags, ...spec.positionals ?? []]) {
|
|
115
|
-
if (arg.required && values[keyOf(arg.name)] === void 0)
|
|
116
|
-
throw new CliUsageError(`Missing required argument: ${arg.name}`);
|
|
117
|
-
}
|
|
118
|
-
return values;
|
|
119
|
-
}
|
|
120
|
-
function renderCliHelp(spec) {
|
|
121
|
-
const describe = (arg) => `${arg.type}${arg.enum ? ` (${arg.enum.join("|")})` : ""}${arg.required ? " required" : ""} ${arg.description ?? ""}`;
|
|
122
|
-
return `Usage: ${spec.command} ${(spec.positionals ?? []).map((arg) => `<${arg.name}${arg.variadic ? "..." : ""}>`).join(" ")} [flags]
|
|
123
|
-
${spec.description ?? ""}
|
|
124
|
-
|
|
125
|
-
Positionals:
|
|
126
|
-
${(spec.positionals ?? []).map((arg) => ` ${arg.name} ${describe(arg)}`).join("\n")}
|
|
127
|
-
Flags:
|
|
128
|
-
${(spec.flags ?? []).map((arg) => ` --${arg.name}${arg.short ? `, -${arg.short}` : ""} ${describe(arg)}`).join("\n")}
|
|
129
|
-
`;
|
|
130
|
-
}
|
|
131
38
|
|
|
132
39
|
// src/surface/plain_dates.ts
|
|
133
40
|
function parsePlainDue(raw, now = Date.now()) {
|
|
134
41
|
const invalid = () => new CliUsageError(
|
|
135
|
-
`Invalid --due "${raw}". Use YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, +3d or
|
|
42
|
+
`Invalid --due "${raw}". Use YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, +Nd (for example +3d), integer epoch milliseconds, or YYYY-MM-DDTHH:mm[:ss[.fraction]][Z|\xB1HH:mm] (no zone means local time).`
|
|
136
43
|
);
|
|
137
44
|
if (/^-?\d+$/.test(raw)) {
|
|
138
45
|
const value = Number(raw);
|
|
@@ -158,7 +65,7 @@ function parsePlainDue(raw, now = Date.now()) {
|
|
|
158
65
|
);
|
|
159
66
|
date.setHours(23, 59, 59, 999);
|
|
160
67
|
} else {
|
|
161
|
-
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})
|
|
68
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})?$/.test(raw))
|
|
162
69
|
throw invalid();
|
|
163
70
|
parsePlainDue(raw.slice(0, 10), now);
|
|
164
71
|
date = new Date(raw);
|
|
@@ -210,6 +117,9 @@ function renderQuestlogPlainResult(result, db, values) {
|
|
|
210
117
|
Missing: ${r.clarification.missing.map((name) => `--${name}`).join(", ")}
|
|
211
118
|
` : `${r.summary}
|
|
212
119
|
${r.error.message}
|
|
120
|
+
`;
|
|
121
|
+
if (r.data.deliveries && !r.data.item)
|
|
122
|
+
return `${r.data.deliveries.map((d) => `${d.id} target ${d.targetId} ${d.status} attempts ${d.attempts} HTTP ${d.httpStatus ?? "-"} next ${new Date(d.nextAttemptAt).toISOString()} events ${d.events.map((e) => e.id).join(", ")}`).join("\n") || "No deliveries"}
|
|
213
123
|
`;
|
|
214
124
|
if (r.data.items) {
|
|
215
125
|
const items = values.limit === void 0 ? r.data.items : r.data.items.slice(0, Math.max(0, Number(values.limit)));
|
|
@@ -235,6 +145,11 @@ ${r.error.message}
|
|
|
235
145
|
]);
|
|
236
146
|
if (detail.outcome != null) fields.push(["outcome", detail.outcome]);
|
|
237
147
|
if (detail.questlineId != null) fields.push(["questline", detail.questlineId]);
|
|
148
|
+
for (const delivery of listDeliveries(db, { questId: detail.id }))
|
|
149
|
+
fields.push([
|
|
150
|
+
"delivery",
|
|
151
|
+
`${delivery.id} target ${delivery.targetId} ${delivery.status} attempts ${delivery.attempts}`
|
|
152
|
+
]);
|
|
238
153
|
const width = Math.max(...fields.map(([label]) => label.length));
|
|
239
154
|
return `${fields.map(([label, value]) => `${label.padEnd(width)}: ${String(value).replace(/[\r\n]+/g, " ")}`).join("\n")}
|
|
240
155
|
`;
|
|
@@ -258,6 +173,34 @@ function questlogPlainCommands() {
|
|
|
258
173
|
const id = { name: "id", type: "integer", required: true };
|
|
259
174
|
const views = reviewQuestlogTool.inputSchema.properties?.view?.enum ?? [];
|
|
260
175
|
const commands = [
|
|
176
|
+
{
|
|
177
|
+
spec: {
|
|
178
|
+
command: "tick",
|
|
179
|
+
description: "Detect events and deliver outbound webhooks once.",
|
|
180
|
+
flags: [{ name: "dry-run", type: "boolean" }]
|
|
181
|
+
},
|
|
182
|
+
tool: "manage_hooks",
|
|
183
|
+
input: (v) => ({ action: "tick", dry_run: v.dryRun ?? false }),
|
|
184
|
+
render: (r, _db, values) => {
|
|
185
|
+
const result = r;
|
|
186
|
+
if (!result.ok || !result.data) return `${result.summary}
|
|
187
|
+
`;
|
|
188
|
+
const d = result.data;
|
|
189
|
+
return `${d.events.length} events found; ${d.sent} deliveries sent, ${d.queued} queued, ${d.retrying} retrying, ${d.failed} failed.
|
|
190
|
+
${values.dryRun ? `${JSON.stringify({ events: d.events, batches: d.batches }, null, 2)}
|
|
191
|
+
` : ""}`;
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
spec: {
|
|
196
|
+
command: "review",
|
|
197
|
+
description: "Review an operational view.",
|
|
198
|
+
positionals: [{ name: "view", type: "string", required: true, enum: views }]
|
|
199
|
+
},
|
|
200
|
+
tool: "review_questlog",
|
|
201
|
+
input: (v) => ({ view: v.view }),
|
|
202
|
+
render: renderQuestlogPlainResult
|
|
203
|
+
},
|
|
261
204
|
{
|
|
262
205
|
spec: {
|
|
263
206
|
command: "add",
|
|
@@ -282,7 +225,10 @@ function questlogPlainCommands() {
|
|
|
282
225
|
"give the title once: either as the first argument or with --title"
|
|
283
226
|
);
|
|
284
227
|
const title = v.positionalTitle ?? v.title;
|
|
285
|
-
if (title === void 0)
|
|
228
|
+
if (title === void 0)
|
|
229
|
+
throw new CliUsageError(
|
|
230
|
+
'Missing required argument: title. Example: questlog add "Write the report" --due tomorrow'
|
|
231
|
+
);
|
|
286
232
|
const quest = {
|
|
287
233
|
title,
|
|
288
234
|
objective: v.objective ?? title
|
|
@@ -370,13 +316,13 @@ function selectedDbPath(options) {
|
|
|
370
316
|
var questlogCliOptions = {
|
|
371
317
|
bin: "ghostpaw-questlog",
|
|
372
318
|
version: questlogVersion,
|
|
373
|
-
versionLine: () => cliVersion(questlogVersion),
|
|
319
|
+
versionLine: (args) => cliVersion(questlogVersion, { args }),
|
|
374
320
|
description: "Local task and calendar library",
|
|
375
321
|
tools: questlogSurfaceTools,
|
|
376
322
|
describeDb: (options) => `Database: ${selectedDbPath(options)}
|
|
377
323
|
Use --db <path> or GHOSTPAW_QUESTLOG_DB to override the default ~/.ghostpaw/questlog.db.`,
|
|
378
324
|
openContext: async (options) => {
|
|
379
|
-
const { openQuestlogDb } = await import('./open_questlog_db-
|
|
325
|
+
const { openQuestlogDb } = await import('./open_questlog_db-6NS6BVBC.js');
|
|
380
326
|
const path = selectedDbPath(options);
|
|
381
327
|
const created = path !== ":memory:" && !existsSync(path);
|
|
382
328
|
const db = await openQuestlogDb(path);
|
|
@@ -386,15 +332,58 @@ Use --db <path> or GHOSTPAW_QUESTLOG_DB to override the default ~/.ghostpaw/ques
|
|
|
386
332
|
},
|
|
387
333
|
closeContext: (db) => db.close(),
|
|
388
334
|
commands: {
|
|
335
|
+
names: ["hook", "watch"],
|
|
336
|
+
run: async (command, args, options, io) => {
|
|
337
|
+
if (command === "show" && args[0]?.startsWith("d_")) {
|
|
338
|
+
const { listDeliveries: listDeliveries2 } = await import('./list_deliveries-WJEJUZIQ.js');
|
|
339
|
+
const { listHooks } = await import('./list_hooks-C5CAA2C7.js');
|
|
340
|
+
const { textOutput } = await import('./text_output-X7F3K23Q.js');
|
|
341
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
342
|
+
io.stdout.write("questlog show <delivery-id> [--json]\n");
|
|
343
|
+
return 0;
|
|
344
|
+
}
|
|
345
|
+
const { openQuestlogDb } = await import('./open_questlog_db-6NS6BVBC.js');
|
|
346
|
+
const db = await openQuestlogDb(selectedDbPath(options));
|
|
347
|
+
try {
|
|
348
|
+
const delivery = listDeliveries2(db, { includeDelivered: true }).find(
|
|
349
|
+
(d) => d.id === args[0]
|
|
350
|
+
);
|
|
351
|
+
if (!delivery) {
|
|
352
|
+
io.stderr.write(`Delivery ${args[0]} not found
|
|
353
|
+
`);
|
|
354
|
+
return 1;
|
|
355
|
+
}
|
|
356
|
+
const target = listHooks(db).find((h) => h.id === delivery.targetId);
|
|
357
|
+
const result = {
|
|
358
|
+
...delivery,
|
|
359
|
+
target: target ?? null,
|
|
360
|
+
eventIds: delivery.events.map((e) => e.id)
|
|
361
|
+
};
|
|
362
|
+
io.stdout.write(
|
|
363
|
+
`${args.includes("--json") ? JSON.stringify(result, null, 2) : textOutput(result)}
|
|
364
|
+
`
|
|
365
|
+
);
|
|
366
|
+
return 0;
|
|
367
|
+
} finally {
|
|
368
|
+
db.close();
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (command !== "hook" && command !== "watch") return void 0;
|
|
372
|
+
const { runHookCommand } = await import('./run_hook_command-BOENYNDT.js');
|
|
373
|
+
return runHookCommand(command, args, io, async () => {
|
|
374
|
+
const { openQuestlogDb } = await import('./open_questlog_db-6NS6BVBC.js');
|
|
375
|
+
return openQuestlogDb(selectedDbPath(options));
|
|
376
|
+
});
|
|
377
|
+
},
|
|
389
378
|
plain: questlogPlainCommands(),
|
|
390
379
|
guides: questlogSkills,
|
|
391
380
|
mcp: async (options) => {
|
|
392
|
-
const { serveQuestlogMcp } = await import('./serve_questlog_mcp-
|
|
381
|
+
const { serveQuestlogMcp } = await import('./serve_questlog_mcp-X524X34F.js');
|
|
393
382
|
await serveQuestlogMcp(options.db === void 0 ? {} : { dbPath: options.db });
|
|
394
383
|
},
|
|
395
384
|
skill: async () => {
|
|
396
|
-
const { renderSkillMarkdown } = await import('./skill_markdown-
|
|
397
|
-
const { questlogSkillSpec } = await import('./questlog_skill_spec-
|
|
385
|
+
const { renderSkillMarkdown } = await import('./skill_markdown-EGKYZ3W2.js');
|
|
386
|
+
const { questlogSkillSpec } = await import('./questlog_skill_spec-ILTCTRYS.js');
|
|
398
387
|
return renderSkillMarkdown(questlogSkillSpec);
|
|
399
388
|
}
|
|
400
389
|
}
|
|
@@ -463,6 +452,12 @@ async function runToolCli(argv, options) {
|
|
|
463
452
|
i--;
|
|
464
453
|
}
|
|
465
454
|
}
|
|
455
|
+
const versionArgs = args.filter((arg) => arg !== "--short" && arg !== "--json");
|
|
456
|
+
if (versionArgs[0] === "--version" || versionArgs[0] === "-v") {
|
|
457
|
+
stdout.write(`${options.versionLine?.(args) ?? options.version}
|
|
458
|
+
`);
|
|
459
|
+
return 0;
|
|
460
|
+
}
|
|
466
461
|
const ctxOptions = db === void 0 ? {} : { db };
|
|
467
462
|
const command = args.shift() ?? "help";
|
|
468
463
|
const normalize = (name2) => name2.replace(/[-_]/g, "").toLowerCase();
|
|
@@ -472,8 +467,14 @@ async function runToolCli(argv, options) {
|
|
|
472
467
|
${options.description}
|
|
473
468
|
|
|
474
469
|
Usage: ${options.bin} [--db path] <command>
|
|
475
|
-
Commands: ${
|
|
470
|
+
Commands: ${[
|
|
471
|
+
...options.commands?.plain?.map((entry) => entry.spec.command) ?? [],
|
|
472
|
+
...options.commands?.names ?? []
|
|
473
|
+
].map((name2) => `${name2}, `).join(
|
|
474
|
+
""
|
|
475
|
+
)}tools [--json], describe <tool>, call <tool> [JSON|-], <tool> --parameter value, mcp, skill
|
|
476
476
|
Options: --help, --version, --compact, --db <path>
|
|
477
|
+
Version formats: --version --short, --version --json
|
|
477
478
|
${options.describeDb ? `${options.describeDb(ctxOptions)}
|
|
478
479
|
` : ""}
|
|
479
480
|
${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")}
|
|
@@ -481,9 +482,11 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
481
482
|
);
|
|
482
483
|
return 0;
|
|
483
484
|
}
|
|
484
|
-
if (["--
|
|
485
|
-
stdout.write(
|
|
486
|
-
`
|
|
485
|
+
if (["tools", "call", "describe"].includes(command) && args.length === 1 && ["--help", "-h"].includes(args[0] ?? "")) {
|
|
486
|
+
stdout.write(
|
|
487
|
+
`Usage: ${options.bin} ${command}${command === "tools" ? " [--json]" : " <tool> [--help]"}
|
|
488
|
+
`
|
|
489
|
+
);
|
|
487
490
|
return 0;
|
|
488
491
|
}
|
|
489
492
|
if (command === "tools") {
|
|
@@ -500,16 +503,21 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
500
503
|
}
|
|
501
504
|
if (command === "skill") {
|
|
502
505
|
if (!options.commands?.skill) return fail("skill command unavailable");
|
|
503
|
-
if (args.length > 1
|
|
504
|
-
|
|
506
|
+
if (args.length > 1 && !args.some((arg) => ["--help", "-h"].includes(arg)))
|
|
507
|
+
return fail(`Usage: ${options.bin} skill [--short | --list | <guide> | --help]`);
|
|
508
|
+
const guide = args.some((arg) => ["--help", "-h"].includes(arg)) ? "--help" : args[0];
|
|
505
509
|
if (guide === "--help" || guide === "-h") {
|
|
506
510
|
stdout.write(
|
|
507
511
|
`Usage:
|
|
508
512
|
${options.bin} skill
|
|
509
513
|
${options.bin} skill --list
|
|
514
|
+
${options.bin} skill --short
|
|
510
515
|
${options.bin} skill <guide>
|
|
511
516
|
`
|
|
512
517
|
);
|
|
518
|
+
} else if (guide === "--short") {
|
|
519
|
+
const full = await options.commands.skill();
|
|
520
|
+
stdout.write(full.split("## Appendix:")[0]?.replace(/^---[\s\S]*?---\n+/, "") ?? full);
|
|
513
521
|
} else if (guide === "--list") {
|
|
514
522
|
stdout.write(
|
|
515
523
|
`${(options.commands.guides ?? []).map((entry) => `${entry.name} ${entry.description.replace(/\s+/g, " ")}`).join("\n")}
|
|
@@ -522,11 +530,22 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
522
530
|
} else stdout.write(await options.commands.skill());
|
|
523
531
|
return 0;
|
|
524
532
|
}
|
|
533
|
+
if (command === "mcp" && (args.includes("--help") || args.includes("-h"))) {
|
|
534
|
+
stdout.write(`${options.bin} mcp [--db path]
|
|
535
|
+
`);
|
|
536
|
+
return 0;
|
|
537
|
+
}
|
|
525
538
|
if (command === "mcp") {
|
|
526
539
|
if (!options.commands?.mcp) return fail("mcp command unavailable");
|
|
527
540
|
await options.commands.mcp(ctxOptions);
|
|
528
541
|
return 0;
|
|
529
542
|
}
|
|
543
|
+
const custom = await options.commands?.run?.(command, args, ctxOptions, {
|
|
544
|
+
stdin,
|
|
545
|
+
stdout,
|
|
546
|
+
stderr
|
|
547
|
+
});
|
|
548
|
+
if (custom !== void 0) return custom;
|
|
530
549
|
const plain = options.commands?.plain?.find((entry) => entry.spec.command === command);
|
|
531
550
|
let plainValues = {};
|
|
532
551
|
if (plain) {
|
|
@@ -556,6 +575,7 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
556
575
|
if (command === "call" || command === "describe") return fail(`Unknown tool: ${name ?? ""}`);
|
|
557
576
|
const suggestion = suggestCommand(command, [
|
|
558
577
|
...options.commands?.plain?.map((entry) => entry.spec.command) ?? [],
|
|
578
|
+
...options.commands?.names ?? [],
|
|
559
579
|
"help",
|
|
560
580
|
"tools",
|
|
561
581
|
"describe",
|
|
@@ -566,26 +586,25 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
566
586
|
]);
|
|
567
587
|
return fail(`Unknown command: ${command}.${suggestion ? ` Did you mean ${suggestion}?` : ""}`);
|
|
568
588
|
}
|
|
569
|
-
if (command === "describe") {
|
|
589
|
+
if (command === "describe" || args.includes("--help") || args.includes("-h")) {
|
|
570
590
|
stdout.write(
|
|
571
591
|
`${tool.name}
|
|
592
|
+
Usage: ${options.bin} ${tool.name} --parameter value [--json]
|
|
572
593
|
${tool.description}
|
|
573
594
|
Use when: ${tool.whenToUse ?? ""}
|
|
574
595
|
Not for: ${tool.whenNotToUse ?? ""}
|
|
575
596
|
Read only: ${tool.readOnly ?? false}
|
|
576
597
|
|
|
577
598
|
Parameter | Type | Required | Description
|
|
578
|
-
${
|
|
579
|
-
tool.inputSchema.properties ?? {}
|
|
580
|
-
).map(
|
|
581
|
-
([key, schema]) => `${key} | ${schema.type ?? "oneOf"} | ${tool.inputSchema.required?.includes(key) ?? false} | ${schema.description ?? ""}`
|
|
582
|
-
).join("\n")}
|
|
599
|
+
${schemaRows(tool.inputSchema).join("\n")}
|
|
583
600
|
|
|
584
601
|
${JSON.stringify(tool.inputSchema, null, 2)}
|
|
585
602
|
`
|
|
586
603
|
);
|
|
587
604
|
return 0;
|
|
588
605
|
}
|
|
606
|
+
const json = args.includes("--json");
|
|
607
|
+
if (!plain && json) args.splice(args.indexOf("--json"), 1);
|
|
589
608
|
let input = {};
|
|
590
609
|
try {
|
|
591
610
|
const readStdin = async () => {
|