@ghostpaw/questlog 0.9.0 → 0.9.2
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 +66 -18
- package/SKILL.md +136 -29
- package/dist/{questlog_skill_spec-JLZH3JL2.js → chunk-6KTQK3ZE.js} +1 -52
- package/dist/chunk-DKH623HU.js +17 -0
- package/dist/chunk-QYSIJ2YN.js +47 -0
- package/dist/{chunk-3Y5F3SMB.js → chunk-UTUQPSGO.js} +179 -77
- package/dist/cli.js +2 -2
- package/dist/{cli_main-ED5BJPSR.js → cli_main-XNZP4TY2.js} +68 -14
- package/dist/index.cjs +147 -2
- package/dist/index.js +147 -2
- package/dist/mcp-server.js +149 -10
- package/dist/mcp.cjs +158 -46
- package/dist/mcp.js +158 -46
- package/dist/questlog_skill_spec-EM6DGGVN.js +74 -0
- package/dist/{serve_questlog_mcp-J4ZHNEOT.js → serve_questlog_mcp-KFUYJB2P.js} +12 -3
- package/dist/{skill_markdown-7HCMSJYR.js → skill_markdown-HXYQ3K6U.js} +34 -6
- package/package.json +6 -3
- package/skills/questlog/SKILL.md +136 -29
- package/dist/chunk-RUSE7ZFF.js +0 -58
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { registerSchemaActions, minimalInput, requiredForAction } from './chunk-QYSIJ2YN.js';
|
|
3
|
+
|
|
2
4
|
// src/questlines/map_questline_row.ts
|
|
3
5
|
function mapQuestlineRow(row) {
|
|
4
6
|
return {
|
|
@@ -1080,8 +1082,181 @@ function listRumors(db) {
|
|
|
1080
1082
|
return db.prepare("SELECT * FROM rumors WHERE deleted_at IS NULL ORDER BY created_at DESC, id DESC").all().map(mapRumorRow);
|
|
1081
1083
|
}
|
|
1082
1084
|
|
|
1085
|
+
// src/surfaces/validate_input.ts
|
|
1086
|
+
function validateInput(schema, input, path = "$") {
|
|
1087
|
+
const errors = [];
|
|
1088
|
+
const matchesType = (type) => {
|
|
1089
|
+
switch (type) {
|
|
1090
|
+
case "object":
|
|
1091
|
+
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
1092
|
+
case "array":
|
|
1093
|
+
return Array.isArray(input);
|
|
1094
|
+
case "integer":
|
|
1095
|
+
return typeof input === "number" && Number.isInteger(input);
|
|
1096
|
+
case "number":
|
|
1097
|
+
return typeof input === "number" && Number.isFinite(input);
|
|
1098
|
+
case "null":
|
|
1099
|
+
return input === null;
|
|
1100
|
+
default:
|
|
1101
|
+
return typeof input === type;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
|
|
1105
|
+
return [`${path}: expected ${String(schema.type)}`];
|
|
1106
|
+
}
|
|
1107
|
+
if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
|
|
1108
|
+
errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
|
|
1109
|
+
const constant = "const" in schema ? schema.const : void 0;
|
|
1110
|
+
if (constant !== void 0 && constant !== input)
|
|
1111
|
+
errors.push(`${path}: expected ${JSON.stringify(constant)}`);
|
|
1112
|
+
if (schema.oneOf) {
|
|
1113
|
+
const branches = schema.oneOf.map((branch) => validateInput(branch, input, path));
|
|
1114
|
+
if (!branches.some((errors2) => errors2.length === 0)) {
|
|
1115
|
+
errors.push(
|
|
1116
|
+
...branches.sort((a, b) => a.length - b.length)[0] ?? [
|
|
1117
|
+
`${path}: must match at least one schema branch`
|
|
1118
|
+
]
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
1123
|
+
const record = input;
|
|
1124
|
+
for (const name of [...schema.required ?? [], ...requiredForAction(schema, record.action)])
|
|
1125
|
+
if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
|
|
1126
|
+
for (const [name, property] of Object.entries(schema.properties ?? {}))
|
|
1127
|
+
if (Object.hasOwn(record, name))
|
|
1128
|
+
errors.push(...validateInput(property, record[name], `${path}.${name}`));
|
|
1129
|
+
}
|
|
1130
|
+
if (Array.isArray(input) && schema.items)
|
|
1131
|
+
input.forEach((value, index) => {
|
|
1132
|
+
errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
|
|
1133
|
+
});
|
|
1134
|
+
return errors;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// src/tools/action_requirements.ts
|
|
1138
|
+
var actionRequirements = {
|
|
1139
|
+
shape_work: {
|
|
1140
|
+
create_quest: ["quest"],
|
|
1141
|
+
create_questline: ["questline"],
|
|
1142
|
+
attach_quest_to_questline: ["questId", "questlineId"],
|
|
1143
|
+
detach_quest_from_questline: ["questId"],
|
|
1144
|
+
dismiss_rumor: ["rumorId"],
|
|
1145
|
+
reopen_rumor: ["rumorId"],
|
|
1146
|
+
settle_rumor: ["rumorId"],
|
|
1147
|
+
update_rumor: ["rumorId"]
|
|
1148
|
+
},
|
|
1149
|
+
manage_repeatable: {
|
|
1150
|
+
create: ["repeatableQuest"],
|
|
1151
|
+
archive: ["repeatableQuestId"],
|
|
1152
|
+
update: ["repeatableQuestId"],
|
|
1153
|
+
spawn_due: ["now"]
|
|
1154
|
+
},
|
|
1155
|
+
organize_work: {
|
|
1156
|
+
add_unlock: ["fromQuestId", "toQuestId"],
|
|
1157
|
+
remove_unlock: ["fromQuestId", "toQuestId"],
|
|
1158
|
+
replace_unlocks: ["fromQuestIds", "toQuestId"],
|
|
1159
|
+
archive_questline: ["questlineId"],
|
|
1160
|
+
set_questline_fields: ["questlineId"]
|
|
1161
|
+
},
|
|
1162
|
+
plan_quest: { revise_objective: ["objective"] },
|
|
1163
|
+
run_quest: {
|
|
1164
|
+
abandon_and_spawn_followups: ["followups"],
|
|
1165
|
+
log_effort: ["effortSeconds"]
|
|
1166
|
+
},
|
|
1167
|
+
reward_work: { add: ["reward"], update: ["reward"], replace_repeatable_template: ["rewards"] }
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
// src/tools/tool_types.ts
|
|
1171
|
+
function withOptionalFields(result, options) {
|
|
1172
|
+
if (options.next && options.next.length > 0) {
|
|
1173
|
+
result.next = options.next;
|
|
1174
|
+
}
|
|
1175
|
+
if (options.warnings && options.warnings.length > 0) {
|
|
1176
|
+
result.warnings = options.warnings;
|
|
1177
|
+
}
|
|
1178
|
+
return result;
|
|
1179
|
+
}
|
|
1180
|
+
function toolWarning(code, message) {
|
|
1181
|
+
return { code, message };
|
|
1182
|
+
}
|
|
1183
|
+
function toolSuccess(summary, data, options = {}) {
|
|
1184
|
+
return withOptionalFields(
|
|
1185
|
+
{
|
|
1186
|
+
ok: true,
|
|
1187
|
+
outcome: "success",
|
|
1188
|
+
summary,
|
|
1189
|
+
entities: options.entities ?? [],
|
|
1190
|
+
data
|
|
1191
|
+
},
|
|
1192
|
+
options
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
function toolNoOp(summary, data, options = {}) {
|
|
1196
|
+
return withOptionalFields(
|
|
1197
|
+
{
|
|
1198
|
+
ok: true,
|
|
1199
|
+
outcome: "no_op",
|
|
1200
|
+
summary,
|
|
1201
|
+
entities: options.entities ?? [],
|
|
1202
|
+
data
|
|
1203
|
+
},
|
|
1204
|
+
options
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
function toolNeedsClarification(code, question, missing, options = {}) {
|
|
1208
|
+
return withOptionalFields(
|
|
1209
|
+
{
|
|
1210
|
+
ok: false,
|
|
1211
|
+
outcome: "needs_clarification",
|
|
1212
|
+
summary: question,
|
|
1213
|
+
entities: options.entities ?? [],
|
|
1214
|
+
clarification: {
|
|
1215
|
+
code,
|
|
1216
|
+
question,
|
|
1217
|
+
missing,
|
|
1218
|
+
options: options.options
|
|
1219
|
+
}
|
|
1220
|
+
},
|
|
1221
|
+
options
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
function toolFailure(kind, code, summary, message, options = {}) {
|
|
1225
|
+
return withOptionalFields(
|
|
1226
|
+
{
|
|
1227
|
+
ok: false,
|
|
1228
|
+
outcome: "error",
|
|
1229
|
+
summary,
|
|
1230
|
+
entities: options.entities ?? [],
|
|
1231
|
+
error: {
|
|
1232
|
+
kind,
|
|
1233
|
+
code,
|
|
1234
|
+
message,
|
|
1235
|
+
recovery: options.recovery,
|
|
1236
|
+
details: options.details
|
|
1237
|
+
}
|
|
1238
|
+
},
|
|
1239
|
+
options
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1083
1243
|
// src/tools/tool_metadata.ts
|
|
1084
1244
|
function defineQuestlogTool(definition) {
|
|
1245
|
+
const requirements = actionRequirements[definition.name];
|
|
1246
|
+
if (requirements) registerSchemaActions(definition.inputSchema, requirements);
|
|
1247
|
+
const handler = definition.handler;
|
|
1248
|
+
definition.handler = (db, input) => {
|
|
1249
|
+
const errors = validateInput(definition.inputSchema, input);
|
|
1250
|
+
if (errors.length) {
|
|
1251
|
+
const action = input?.action;
|
|
1252
|
+
const example = minimalInput(definition.inputSchema, action);
|
|
1253
|
+
const message = errors.join("; ");
|
|
1254
|
+
return toolFailure("protocol", "invalid_input", message, message, {
|
|
1255
|
+
recovery: `${message}; pass ${JSON.stringify(example)}`
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
return handler(db, input);
|
|
1259
|
+
};
|
|
1085
1260
|
return definition;
|
|
1086
1261
|
}
|
|
1087
1262
|
function stringSchema(description, options = {}) {
|
|
@@ -1243,79 +1418,6 @@ function summarizeCount(count, singular, plural = `${singular}s`) {
|
|
|
1243
1418
|
return `Found ${count} ${plural}.`;
|
|
1244
1419
|
}
|
|
1245
1420
|
|
|
1246
|
-
// src/tools/tool_types.ts
|
|
1247
|
-
function withOptionalFields(result, options) {
|
|
1248
|
-
if (options.next && options.next.length > 0) {
|
|
1249
|
-
result.next = options.next;
|
|
1250
|
-
}
|
|
1251
|
-
if (options.warnings && options.warnings.length > 0) {
|
|
1252
|
-
result.warnings = options.warnings;
|
|
1253
|
-
}
|
|
1254
|
-
return result;
|
|
1255
|
-
}
|
|
1256
|
-
function toolWarning(code, message) {
|
|
1257
|
-
return { code, message };
|
|
1258
|
-
}
|
|
1259
|
-
function toolSuccess(summary, data, options = {}) {
|
|
1260
|
-
return withOptionalFields(
|
|
1261
|
-
{
|
|
1262
|
-
ok: true,
|
|
1263
|
-
outcome: "success",
|
|
1264
|
-
summary,
|
|
1265
|
-
entities: options.entities ?? [],
|
|
1266
|
-
data
|
|
1267
|
-
},
|
|
1268
|
-
options
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1271
|
-
function toolNoOp(summary, data, options = {}) {
|
|
1272
|
-
return withOptionalFields(
|
|
1273
|
-
{
|
|
1274
|
-
ok: true,
|
|
1275
|
-
outcome: "no_op",
|
|
1276
|
-
summary,
|
|
1277
|
-
entities: options.entities ?? [],
|
|
1278
|
-
data
|
|
1279
|
-
},
|
|
1280
|
-
options
|
|
1281
|
-
);
|
|
1282
|
-
}
|
|
1283
|
-
function toolNeedsClarification(code, question, missing, options = {}) {
|
|
1284
|
-
return withOptionalFields(
|
|
1285
|
-
{
|
|
1286
|
-
ok: false,
|
|
1287
|
-
outcome: "needs_clarification",
|
|
1288
|
-
summary: question,
|
|
1289
|
-
entities: options.entities ?? [],
|
|
1290
|
-
clarification: {
|
|
1291
|
-
code,
|
|
1292
|
-
question,
|
|
1293
|
-
missing,
|
|
1294
|
-
options: options.options
|
|
1295
|
-
}
|
|
1296
|
-
},
|
|
1297
|
-
options
|
|
1298
|
-
);
|
|
1299
|
-
}
|
|
1300
|
-
function toolFailure(kind, code, summary, message, options = {}) {
|
|
1301
|
-
return withOptionalFields(
|
|
1302
|
-
{
|
|
1303
|
-
ok: false,
|
|
1304
|
-
outcome: "error",
|
|
1305
|
-
summary,
|
|
1306
|
-
entities: options.entities ?? [],
|
|
1307
|
-
error: {
|
|
1308
|
-
kind,
|
|
1309
|
-
code,
|
|
1310
|
-
message,
|
|
1311
|
-
recovery: options.recovery,
|
|
1312
|
-
details: options.details
|
|
1313
|
-
}
|
|
1314
|
-
},
|
|
1315
|
-
options
|
|
1316
|
-
);
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
1421
|
// src/tools/review_questlog_tool.ts
|
|
1320
1422
|
function hasQuestFilters(filters) {
|
|
1321
1423
|
return Boolean(
|
|
@@ -3191,7 +3293,7 @@ var rewardWorkTool = defineQuestlogTool({
|
|
|
3191
3293
|
name: stringSchema("Reward name."),
|
|
3192
3294
|
now: integerSchema("Optional update timestamp for the update action.")
|
|
3193
3295
|
},
|
|
3194
|
-
[]
|
|
3296
|
+
["kind", "name"]
|
|
3195
3297
|
),
|
|
3196
3298
|
rewards: arraySchema(
|
|
3197
3299
|
objectSchema(
|
|
@@ -4018,7 +4120,7 @@ var shapeWorkTool = defineQuestlogTool({
|
|
|
4018
4120
|
title: stringSchema("Questline title."),
|
|
4019
4121
|
description: stringSchema("Optional questline description.")
|
|
4020
4122
|
},
|
|
4021
|
-
[]
|
|
4123
|
+
["title"]
|
|
4022
4124
|
),
|
|
4023
4125
|
rumorId: integerSchema("Rumor to settle, dismiss, or reopen."),
|
|
4024
4126
|
dismissedAt: integerSchema("Optional dismissal timestamp."),
|
|
@@ -4300,9 +4402,9 @@ var questlogSurfaceTools = questlogTools.map(
|
|
|
4300
4402
|
whenNotToUse: tool.whenNotToUse ?? "",
|
|
4301
4403
|
readOnly: tool.readOnly,
|
|
4302
4404
|
sideEffects: tool.sideEffects,
|
|
4303
|
-
inputSchema:
|
|
4405
|
+
inputSchema: tool.inputSchema,
|
|
4304
4406
|
handler: tool.handler
|
|
4305
4407
|
})
|
|
4306
4408
|
);
|
|
4307
4409
|
|
|
4308
|
-
export { getQuestDetail, questlogSurfaceTools, reviewQuestlogTool };
|
|
4410
|
+
export { getQuestDetail, questlogSurfaceTools, reviewQuestlogTool, validateInput };
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
function checkNodeVersion(version, stderr) {
|
|
4
4
|
if (Number(version.split(".")[0]) >= 24) return true;
|
|
5
5
|
stderr.write(
|
|
6
|
-
`questlog needs Node 24+ (found ${version}). Install Node 24 or put it first on PATH.
|
|
6
|
+
`questlog needs Node 24+ (found ${version}). Install Node 24+ (e.g. via nvm, mise or your package manager) or put it first on PATH.
|
|
7
7
|
`
|
|
8
8
|
);
|
|
9
9
|
return false;
|
|
@@ -13,5 +13,5 @@ function checkNodeVersion(version, stderr) {
|
|
|
13
13
|
if (!checkNodeVersion(process.versions.node, process.stderr)) {
|
|
14
14
|
process.exitCode = 2;
|
|
15
15
|
} else {
|
|
16
|
-
await import('./cli_main-
|
|
16
|
+
await import('./cli_main-XNZP4TY2.js');
|
|
17
17
|
}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { isErrorResult, questlogVersion, resolveQuestlogDbPath } from './chunk-DKH623HU.js';
|
|
3
|
+
import { questlogSkills } from './chunk-6KTQK3ZE.js';
|
|
4
|
+
import { reviewQuestlogTool, validateInput, getQuestDetail, questlogSurfaceTools } from './chunk-UTUQPSGO.js';
|
|
5
|
+
import { minimalInput } from './chunk-QYSIJ2YN.js';
|
|
6
|
+
import { isSea } from 'node:sea';
|
|
4
7
|
import { readFileSync, existsSync } from 'node:fs';
|
|
5
8
|
import { resolve } from 'node:path';
|
|
6
9
|
|
|
10
|
+
var npmEntry = false;
|
|
11
|
+
function markNpmEntry() {
|
|
12
|
+
npmEntry = true;
|
|
13
|
+
}
|
|
14
|
+
function cliVersion(version, {
|
|
15
|
+
sea = isSea,
|
|
16
|
+
npm = npmEntry,
|
|
17
|
+
platform = process.platform,
|
|
18
|
+
arch = process.arch
|
|
19
|
+
} = {}) {
|
|
20
|
+
let binary = false;
|
|
21
|
+
try {
|
|
22
|
+
binary = sea();
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
const target = `${platform === "win32" ? "windows" : platform}-${arch}`;
|
|
26
|
+
return `questlog ${version} (${binary ? `binary, ${target}` : npm ? "npm" : "library"})`;
|
|
27
|
+
}
|
|
7
28
|
var CliUsageError = class extends Error {
|
|
8
29
|
exitCode = 2;
|
|
9
30
|
};
|
|
@@ -71,7 +92,7 @@ function parseCliArgs(argv, spec) {
|
|
|
71
92
|
if (arg.type === "boolean" && raw === void 0) raw = negative ? "false" : "true";
|
|
72
93
|
if (raw === void 0) {
|
|
73
94
|
const next = argv[i + 1];
|
|
74
|
-
if (next === void 0 ||
|
|
95
|
+
if (next === void 0 || /^--[a-z]/i.test(next))
|
|
75
96
|
throw new CliUsageError(`Missing value: --${arg.name}`);
|
|
76
97
|
raw = next;
|
|
77
98
|
i++;
|
|
@@ -202,7 +223,7 @@ ${r.error.message}
|
|
|
202
223
|
["title", detail.title],
|
|
203
224
|
["objective", detail.objective],
|
|
204
225
|
["state", detail.state],
|
|
205
|
-
["tags", detail.tagNames.map((tag) => `#${tag}`).join(" ")],
|
|
226
|
+
["tags", detail.tagNames.length ? detail.tagNames.map((tag) => `#${tag}`).join(" ") : "-"],
|
|
206
227
|
["due", detail.effectiveDueAt == null ? "-" : formatPlainDate(detail.effectiveDueAt, true)],
|
|
207
228
|
["created", formatPlainDate(detail.createdAt, true)]
|
|
208
229
|
];
|
|
@@ -240,9 +261,10 @@ function questlogPlainCommands() {
|
|
|
240
261
|
{
|
|
241
262
|
spec: {
|
|
242
263
|
command: "add",
|
|
243
|
-
description:
|
|
264
|
+
description: 'Create a quest: add "My title" or add --title "My title". Objective defaults to the title.',
|
|
265
|
+
positionals: [{ name: "positionalTitle", type: "string" }],
|
|
244
266
|
flags: [
|
|
245
|
-
{ name: "title", type: "string"
|
|
267
|
+
{ name: "title", type: "string" },
|
|
246
268
|
{ name: "tag", type: "array" },
|
|
247
269
|
{ name: "objective", type: "string" },
|
|
248
270
|
{
|
|
@@ -255,9 +277,15 @@ function questlogPlainCommands() {
|
|
|
255
277
|
},
|
|
256
278
|
tool: "shape_work",
|
|
257
279
|
input: (v) => {
|
|
280
|
+
if (v.title !== void 0 && v.positionalTitle !== void 0)
|
|
281
|
+
throw new CliUsageError(
|
|
282
|
+
"give the title once: either as the first argument or with --title"
|
|
283
|
+
);
|
|
284
|
+
const title = v.positionalTitle ?? v.title;
|
|
285
|
+
if (title === void 0) throw new CliUsageError("Missing required argument: title");
|
|
258
286
|
const quest = {
|
|
259
|
-
title
|
|
260
|
-
objective: v.objective ??
|
|
287
|
+
title,
|
|
288
|
+
objective: v.objective ?? title
|
|
261
289
|
};
|
|
262
290
|
if (v.tag !== void 0)
|
|
263
291
|
quest.tags = v.tag.flatMap(
|
|
@@ -342,6 +370,7 @@ function selectedDbPath(options) {
|
|
|
342
370
|
var questlogCliOptions = {
|
|
343
371
|
bin: "ghostpaw-questlog",
|
|
344
372
|
version: questlogVersion,
|
|
373
|
+
versionLine: () => cliVersion(questlogVersion),
|
|
345
374
|
description: "Local task and calendar library",
|
|
346
375
|
tools: questlogSurfaceTools,
|
|
347
376
|
describeDb: (options) => `Database: ${selectedDbPath(options)}
|
|
@@ -358,13 +387,14 @@ Use --db <path> or GHOSTPAW_QUESTLOG_DB to override the default ~/.ghostpaw/ques
|
|
|
358
387
|
closeContext: (db) => db.close(),
|
|
359
388
|
commands: {
|
|
360
389
|
plain: questlogPlainCommands(),
|
|
390
|
+
guides: questlogSkills,
|
|
361
391
|
mcp: async (options) => {
|
|
362
|
-
const { serveQuestlogMcp } = await import('./serve_questlog_mcp-
|
|
392
|
+
const { serveQuestlogMcp } = await import('./serve_questlog_mcp-KFUYJB2P.js');
|
|
363
393
|
await serveQuestlogMcp(options.db === void 0 ? {} : { dbPath: options.db });
|
|
364
394
|
},
|
|
365
395
|
skill: async () => {
|
|
366
|
-
const { renderSkillMarkdown } = await import('./skill_markdown-
|
|
367
|
-
const { questlogSkillSpec } = await import('./questlog_skill_spec-
|
|
396
|
+
const { renderSkillMarkdown } = await import('./skill_markdown-HXYQ3K6U.js');
|
|
397
|
+
const { questlogSkillSpec } = await import('./questlog_skill_spec-EM6DGGVN.js');
|
|
368
398
|
return renderSkillMarkdown(questlogSkillSpec);
|
|
369
399
|
}
|
|
370
400
|
}
|
|
@@ -452,7 +482,7 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
452
482
|
return 0;
|
|
453
483
|
}
|
|
454
484
|
if (["--version", "-v"].includes(command)) {
|
|
455
|
-
stdout.write(`${options.version}
|
|
485
|
+
stdout.write(`${options.versionLine?.() ?? options.version}
|
|
456
486
|
`);
|
|
457
487
|
return 0;
|
|
458
488
|
}
|
|
@@ -470,7 +500,26 @@ ${options.tools.map((tool2) => `${tool2.name} ${tool2.description}`).join("\n")
|
|
|
470
500
|
}
|
|
471
501
|
if (command === "skill") {
|
|
472
502
|
if (!options.commands?.skill) return fail("skill command unavailable");
|
|
473
|
-
|
|
503
|
+
if (args.length > 1) return fail(`Usage: ${options.bin} skill [--list | <guide> | --help]`);
|
|
504
|
+
const guide = args[0];
|
|
505
|
+
if (guide === "--help" || guide === "-h") {
|
|
506
|
+
stdout.write(
|
|
507
|
+
`Usage:
|
|
508
|
+
${options.bin} skill
|
|
509
|
+
${options.bin} skill --list
|
|
510
|
+
${options.bin} skill <guide>
|
|
511
|
+
`
|
|
512
|
+
);
|
|
513
|
+
} else if (guide === "--list") {
|
|
514
|
+
stdout.write(
|
|
515
|
+
`${(options.commands.guides ?? []).map((entry) => `${entry.name} ${entry.description.replace(/\s+/g, " ")}`).join("\n")}
|
|
516
|
+
`
|
|
517
|
+
);
|
|
518
|
+
} else if (guide) {
|
|
519
|
+
const entry = options.commands.guides?.find((entry2) => entry2.name === guide);
|
|
520
|
+
if (!entry) return fail(`unknown guide ${guide}; run ${options.bin} skill --list`);
|
|
521
|
+
stdout.write(entry.content);
|
|
522
|
+
} else stdout.write(await options.commands.skill());
|
|
474
523
|
return 0;
|
|
475
524
|
}
|
|
476
525
|
if (command === "mcp") {
|
|
@@ -599,7 +648,11 @@ ${JSON.stringify(tool.inputSchema, null, 2)}
|
|
|
599
648
|
return fail(`Invalid input: ${cause instanceof Error ? cause.message : String(cause)}`, 1);
|
|
600
649
|
}
|
|
601
650
|
const errors = validateInput(tool.inputSchema, input);
|
|
602
|
-
if (errors.length)
|
|
651
|
+
if (errors.length)
|
|
652
|
+
return fail(
|
|
653
|
+
`${errors.join("\n")}; pass ${JSON.stringify(minimalInput(tool.inputSchema, input?.action))}`,
|
|
654
|
+
1
|
|
655
|
+
);
|
|
603
656
|
let context;
|
|
604
657
|
try {
|
|
605
658
|
context = await options.openContext(ctxOptions);
|
|
@@ -623,4 +676,5 @@ ${JSON.stringify(tool.inputSchema, null, 2)}
|
|
|
623
676
|
}
|
|
624
677
|
|
|
625
678
|
// src/cli_main.ts
|
|
679
|
+
markNpmEntry();
|
|
626
680
|
process.exitCode = await runToolCli(process.argv.slice(2), questlogCliOptions);
|
package/dist/index.cjs
CHANGED
|
@@ -3183,8 +3183,153 @@ function translateToolError(error, options = {}) {
|
|
|
3183
3183
|
);
|
|
3184
3184
|
}
|
|
3185
3185
|
|
|
3186
|
+
// src/surfaces/schema_actions.ts
|
|
3187
|
+
var requirements = /* @__PURE__ */ new WeakMap();
|
|
3188
|
+
function registerSchemaActions(schema, actions) {
|
|
3189
|
+
requirements.set(schema, actions);
|
|
3190
|
+
}
|
|
3191
|
+
function requiredForAction(schema, action) {
|
|
3192
|
+
return requirements.get(schema)?.[String(action)] ?? [];
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3195
|
+
// src/surfaces/schema_examples.ts
|
|
3196
|
+
function minimalInput(schema, action, name = "") {
|
|
3197
|
+
const constant = "const" in schema ? schema.const : void 0;
|
|
3198
|
+
if (constant !== void 0) return constant;
|
|
3199
|
+
if (schema.enum)
|
|
3200
|
+
return action !== void 0 && schema.enum.includes(action) ? action : schema.enum[0];
|
|
3201
|
+
const branch = schema.oneOf?.[0];
|
|
3202
|
+
if (schema.type === "object" || schema.properties) {
|
|
3203
|
+
action ??= schema.properties?.action?.enum?.[0];
|
|
3204
|
+
const properties = { ...schema.properties, ...branch?.properties };
|
|
3205
|
+
return Object.fromEntries(
|
|
3206
|
+
[
|
|
3207
|
+
.../* @__PURE__ */ new Set([
|
|
3208
|
+
...schema.required ?? [],
|
|
3209
|
+
...requiredForAction(schema, action),
|
|
3210
|
+
...schema.properties?.outcome && ["finish", "abandon", "abandon_and_spawn_followups"].includes(String(action)) ? ["outcome"] : [],
|
|
3211
|
+
...branch?.required ?? []
|
|
3212
|
+
])
|
|
3213
|
+
].map((key) => [
|
|
3214
|
+
key,
|
|
3215
|
+
minimalInput(properties[key] ?? {}, key === "action" ? action : void 0, key)
|
|
3216
|
+
])
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
if (branch) return minimalInput(branch, action, name);
|
|
3220
|
+
if (schema.type === "array") return [minimalInput(schema.items ?? {}, void 0, name)];
|
|
3221
|
+
if (schema.type === "integer" || schema.type === "number")
|
|
3222
|
+
return name === "anchorAt" ? 18e11 : name === "toQuestId" ? 2 : 1;
|
|
3223
|
+
if (schema.type === "boolean") return false;
|
|
3224
|
+
if (schema.type === "null") return null;
|
|
3225
|
+
if (name === "rrule") return "FREQ=WEEKLY";
|
|
3226
|
+
if (name === "title") return "Review release notes";
|
|
3227
|
+
if (name === "objective") return "Check changes against the release";
|
|
3228
|
+
return "release";
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
// src/surfaces/validate_input.ts
|
|
3232
|
+
function validateInput(schema, input, path = "$") {
|
|
3233
|
+
const errors = [];
|
|
3234
|
+
const matchesType = (type) => {
|
|
3235
|
+
switch (type) {
|
|
3236
|
+
case "object":
|
|
3237
|
+
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
3238
|
+
case "array":
|
|
3239
|
+
return Array.isArray(input);
|
|
3240
|
+
case "integer":
|
|
3241
|
+
return typeof input === "number" && Number.isInteger(input);
|
|
3242
|
+
case "number":
|
|
3243
|
+
return typeof input === "number" && Number.isFinite(input);
|
|
3244
|
+
case "null":
|
|
3245
|
+
return input === null;
|
|
3246
|
+
default:
|
|
3247
|
+
return typeof input === type;
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
|
|
3251
|
+
return [`${path}: expected ${String(schema.type)}`];
|
|
3252
|
+
}
|
|
3253
|
+
if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
|
|
3254
|
+
errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
|
|
3255
|
+
const constant = "const" in schema ? schema.const : void 0;
|
|
3256
|
+
if (constant !== void 0 && constant !== input)
|
|
3257
|
+
errors.push(`${path}: expected ${JSON.stringify(constant)}`);
|
|
3258
|
+
if (schema.oneOf) {
|
|
3259
|
+
const branches = schema.oneOf.map((branch) => validateInput(branch, input, path));
|
|
3260
|
+
if (!branches.some((errors2) => errors2.length === 0)) {
|
|
3261
|
+
errors.push(
|
|
3262
|
+
...branches.sort((a, b) => a.length - b.length)[0] ?? [
|
|
3263
|
+
`${path}: must match at least one schema branch`
|
|
3264
|
+
]
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
if (typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
3269
|
+
const record = input;
|
|
3270
|
+
for (const name of [...schema.required ?? [], ...requiredForAction(schema, record.action)])
|
|
3271
|
+
if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
|
|
3272
|
+
for (const [name, property] of Object.entries(schema.properties ?? {}))
|
|
3273
|
+
if (Object.hasOwn(record, name))
|
|
3274
|
+
errors.push(...validateInput(property, record[name], `${path}.${name}`));
|
|
3275
|
+
}
|
|
3276
|
+
if (Array.isArray(input) && schema.items)
|
|
3277
|
+
input.forEach((value, index) => {
|
|
3278
|
+
errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
|
|
3279
|
+
});
|
|
3280
|
+
return errors;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
// src/tools/action_requirements.ts
|
|
3284
|
+
var actionRequirements = {
|
|
3285
|
+
shape_work: {
|
|
3286
|
+
create_quest: ["quest"],
|
|
3287
|
+
create_questline: ["questline"],
|
|
3288
|
+
attach_quest_to_questline: ["questId", "questlineId"],
|
|
3289
|
+
detach_quest_from_questline: ["questId"],
|
|
3290
|
+
dismiss_rumor: ["rumorId"],
|
|
3291
|
+
reopen_rumor: ["rumorId"],
|
|
3292
|
+
settle_rumor: ["rumorId"],
|
|
3293
|
+
update_rumor: ["rumorId"]
|
|
3294
|
+
},
|
|
3295
|
+
manage_repeatable: {
|
|
3296
|
+
create: ["repeatableQuest"],
|
|
3297
|
+
archive: ["repeatableQuestId"],
|
|
3298
|
+
update: ["repeatableQuestId"],
|
|
3299
|
+
spawn_due: ["now"]
|
|
3300
|
+
},
|
|
3301
|
+
organize_work: {
|
|
3302
|
+
add_unlock: ["fromQuestId", "toQuestId"],
|
|
3303
|
+
remove_unlock: ["fromQuestId", "toQuestId"],
|
|
3304
|
+
replace_unlocks: ["fromQuestIds", "toQuestId"],
|
|
3305
|
+
archive_questline: ["questlineId"],
|
|
3306
|
+
set_questline_fields: ["questlineId"]
|
|
3307
|
+
},
|
|
3308
|
+
plan_quest: { revise_objective: ["objective"] },
|
|
3309
|
+
run_quest: {
|
|
3310
|
+
abandon_and_spawn_followups: ["followups"],
|
|
3311
|
+
log_effort: ["effortSeconds"]
|
|
3312
|
+
},
|
|
3313
|
+
reward_work: { add: ["reward"], update: ["reward"], replace_repeatable_template: ["rewards"] }
|
|
3314
|
+
};
|
|
3315
|
+
|
|
3186
3316
|
// src/tools/tool_metadata.ts
|
|
3187
3317
|
function defineQuestlogTool(definition) {
|
|
3318
|
+
const requirements2 = actionRequirements[definition.name];
|
|
3319
|
+
if (requirements2) registerSchemaActions(definition.inputSchema, requirements2);
|
|
3320
|
+
const handler = definition.handler;
|
|
3321
|
+
definition.handler = (db, input) => {
|
|
3322
|
+
const errors = validateInput(definition.inputSchema, input);
|
|
3323
|
+
if (errors.length) {
|
|
3324
|
+
const action = input?.action;
|
|
3325
|
+
const example = minimalInput(definition.inputSchema, action);
|
|
3326
|
+
const message = errors.join("; ");
|
|
3327
|
+
return toolFailure("protocol", "invalid_input", message, message, {
|
|
3328
|
+
recovery: `${message}; pass ${JSON.stringify(example)}`
|
|
3329
|
+
});
|
|
3330
|
+
}
|
|
3331
|
+
return handler(db, input);
|
|
3332
|
+
};
|
|
3188
3333
|
return definition;
|
|
3189
3334
|
}
|
|
3190
3335
|
function stringSchema(description, options = {}) {
|
|
@@ -4727,7 +4872,7 @@ var rewardWorkTool = defineQuestlogTool({
|
|
|
4727
4872
|
name: stringSchema("Reward name."),
|
|
4728
4873
|
now: integerSchema("Optional update timestamp for the update action.")
|
|
4729
4874
|
},
|
|
4730
|
-
[]
|
|
4875
|
+
["kind", "name"]
|
|
4731
4876
|
),
|
|
4732
4877
|
rewards: arraySchema(
|
|
4733
4878
|
objectSchema(
|
|
@@ -5393,7 +5538,7 @@ var shapeWorkTool = defineQuestlogTool({
|
|
|
5393
5538
|
title: stringSchema("Questline title."),
|
|
5394
5539
|
description: stringSchema("Optional questline description.")
|
|
5395
5540
|
},
|
|
5396
|
-
[]
|
|
5541
|
+
["title"]
|
|
5397
5542
|
),
|
|
5398
5543
|
rumorId: integerSchema("Rumor to settle, dismiss, or reopen."),
|
|
5399
5544
|
dismissedAt: integerSchema("Optional dismissal timestamp."),
|