@ghostpaw/questlog 0.9.1 → 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 +135 -30
- package/dist/{questlog_skill_spec-LOQ2FNOF.js → chunk-6KTQK3ZE.js} +1 -54
- 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 +1 -1
- package/dist/{cli_main-ELAKW6KW.js → cli_main-XNZP4TY2.js} +67 -13
- 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-QSHMNNFT.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 +135 -30
- package/dist/chunk-KRQDV4KF.js +0 -58
package/dist/mcp.js
CHANGED
|
@@ -384,7 +384,7 @@ async function openQuestlogDb(path) {
|
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
// src/version.ts
|
|
387
|
-
var questlogVersion = "0.9.
|
|
387
|
+
var questlogVersion = "0.9.2";
|
|
388
388
|
|
|
389
389
|
// src/surface/questlog_mcp_instructions.ts
|
|
390
390
|
var questlogMcpInstructions = "Questlog manages local tasks, calendar commitments, and recurring work. Search before creating work, inspect before changing it, and keep uncertain work as rumors. Use unlock prerequisites to sequence work. run_quest refuses blocked starts unless force is true. Review commitments and resolve work with an honest outcome.";
|
|
@@ -630,8 +630,153 @@ function translateToolError(error, options = {}) {
|
|
|
630
630
|
);
|
|
631
631
|
}
|
|
632
632
|
|
|
633
|
+
// src/surfaces/schema_actions.ts
|
|
634
|
+
var requirements = /* @__PURE__ */ new WeakMap();
|
|
635
|
+
function registerSchemaActions(schema, actions) {
|
|
636
|
+
requirements.set(schema, actions);
|
|
637
|
+
}
|
|
638
|
+
function requiredForAction(schema, action) {
|
|
639
|
+
return requirements.get(schema)?.[String(action)] ?? [];
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// src/surfaces/schema_examples.ts
|
|
643
|
+
function minimalInput(schema, action, name = "") {
|
|
644
|
+
const constant = "const" in schema ? schema.const : void 0;
|
|
645
|
+
if (constant !== void 0) return constant;
|
|
646
|
+
if (schema.enum)
|
|
647
|
+
return action !== void 0 && schema.enum.includes(action) ? action : schema.enum[0];
|
|
648
|
+
const branch = schema.oneOf?.[0];
|
|
649
|
+
if (schema.type === "object" || schema.properties) {
|
|
650
|
+
action ??= schema.properties?.action?.enum?.[0];
|
|
651
|
+
const properties = { ...schema.properties, ...branch?.properties };
|
|
652
|
+
return Object.fromEntries(
|
|
653
|
+
[
|
|
654
|
+
.../* @__PURE__ */ new Set([
|
|
655
|
+
...schema.required ?? [],
|
|
656
|
+
...requiredForAction(schema, action),
|
|
657
|
+
...schema.properties?.outcome && ["finish", "abandon", "abandon_and_spawn_followups"].includes(String(action)) ? ["outcome"] : [],
|
|
658
|
+
...branch?.required ?? []
|
|
659
|
+
])
|
|
660
|
+
].map((key) => [
|
|
661
|
+
key,
|
|
662
|
+
minimalInput(properties[key] ?? {}, key === "action" ? action : void 0, key)
|
|
663
|
+
])
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
if (branch) return minimalInput(branch, action, name);
|
|
667
|
+
if (schema.type === "array") return [minimalInput(schema.items ?? {}, void 0, name)];
|
|
668
|
+
if (schema.type === "integer" || schema.type === "number")
|
|
669
|
+
return name === "anchorAt" ? 18e11 : name === "toQuestId" ? 2 : 1;
|
|
670
|
+
if (schema.type === "boolean") return false;
|
|
671
|
+
if (schema.type === "null") return null;
|
|
672
|
+
if (name === "rrule") return "FREQ=WEEKLY";
|
|
673
|
+
if (name === "title") return "Review release notes";
|
|
674
|
+
if (name === "objective") return "Check changes against the release";
|
|
675
|
+
return "release";
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// src/surfaces/validate_input.ts
|
|
679
|
+
function validateInput(schema, input, path = "$") {
|
|
680
|
+
const errors = [];
|
|
681
|
+
const matchesType = (type) => {
|
|
682
|
+
switch (type) {
|
|
683
|
+
case "object":
|
|
684
|
+
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
685
|
+
case "array":
|
|
686
|
+
return Array.isArray(input);
|
|
687
|
+
case "integer":
|
|
688
|
+
return typeof input === "number" && Number.isInteger(input);
|
|
689
|
+
case "number":
|
|
690
|
+
return typeof input === "number" && Number.isFinite(input);
|
|
691
|
+
case "null":
|
|
692
|
+
return input === null;
|
|
693
|
+
default:
|
|
694
|
+
return typeof input === type;
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
|
|
698
|
+
return [`${path}: expected ${String(schema.type)}`];
|
|
699
|
+
}
|
|
700
|
+
if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
|
|
701
|
+
errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
|
|
702
|
+
const constant = "const" in schema ? schema.const : void 0;
|
|
703
|
+
if (constant !== void 0 && constant !== input)
|
|
704
|
+
errors.push(`${path}: expected ${JSON.stringify(constant)}`);
|
|
705
|
+
if (schema.oneOf) {
|
|
706
|
+
const branches = schema.oneOf.map((branch) => validateInput(branch, input, path));
|
|
707
|
+
if (!branches.some((errors2) => errors2.length === 0)) {
|
|
708
|
+
errors.push(
|
|
709
|
+
...branches.sort((a, b) => a.length - b.length)[0] ?? [
|
|
710
|
+
`${path}: must match at least one schema branch`
|
|
711
|
+
]
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if (typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
716
|
+
const record = input;
|
|
717
|
+
for (const name of [...schema.required ?? [], ...requiredForAction(schema, record.action)])
|
|
718
|
+
if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
|
|
719
|
+
for (const [name, property] of Object.entries(schema.properties ?? {}))
|
|
720
|
+
if (Object.hasOwn(record, name))
|
|
721
|
+
errors.push(...validateInput(property, record[name], `${path}.${name}`));
|
|
722
|
+
}
|
|
723
|
+
if (Array.isArray(input) && schema.items)
|
|
724
|
+
input.forEach((value, index) => {
|
|
725
|
+
errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
|
|
726
|
+
});
|
|
727
|
+
return errors;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// src/tools/action_requirements.ts
|
|
731
|
+
var actionRequirements = {
|
|
732
|
+
shape_work: {
|
|
733
|
+
create_quest: ["quest"],
|
|
734
|
+
create_questline: ["questline"],
|
|
735
|
+
attach_quest_to_questline: ["questId", "questlineId"],
|
|
736
|
+
detach_quest_from_questline: ["questId"],
|
|
737
|
+
dismiss_rumor: ["rumorId"],
|
|
738
|
+
reopen_rumor: ["rumorId"],
|
|
739
|
+
settle_rumor: ["rumorId"],
|
|
740
|
+
update_rumor: ["rumorId"]
|
|
741
|
+
},
|
|
742
|
+
manage_repeatable: {
|
|
743
|
+
create: ["repeatableQuest"],
|
|
744
|
+
archive: ["repeatableQuestId"],
|
|
745
|
+
update: ["repeatableQuestId"],
|
|
746
|
+
spawn_due: ["now"]
|
|
747
|
+
},
|
|
748
|
+
organize_work: {
|
|
749
|
+
add_unlock: ["fromQuestId", "toQuestId"],
|
|
750
|
+
remove_unlock: ["fromQuestId", "toQuestId"],
|
|
751
|
+
replace_unlocks: ["fromQuestIds", "toQuestId"],
|
|
752
|
+
archive_questline: ["questlineId"],
|
|
753
|
+
set_questline_fields: ["questlineId"]
|
|
754
|
+
},
|
|
755
|
+
plan_quest: { revise_objective: ["objective"] },
|
|
756
|
+
run_quest: {
|
|
757
|
+
abandon_and_spawn_followups: ["followups"],
|
|
758
|
+
log_effort: ["effortSeconds"]
|
|
759
|
+
},
|
|
760
|
+
reward_work: { add: ["reward"], update: ["reward"], replace_repeatable_template: ["rewards"] }
|
|
761
|
+
};
|
|
762
|
+
|
|
633
763
|
// src/tools/tool_metadata.ts
|
|
634
764
|
function defineQuestlogTool(definition) {
|
|
765
|
+
const requirements2 = actionRequirements[definition.name];
|
|
766
|
+
if (requirements2) registerSchemaActions(definition.inputSchema, requirements2);
|
|
767
|
+
const handler = definition.handler;
|
|
768
|
+
definition.handler = (db, input) => {
|
|
769
|
+
const errors = validateInput(definition.inputSchema, input);
|
|
770
|
+
if (errors.length) {
|
|
771
|
+
const action = input?.action;
|
|
772
|
+
const example = minimalInput(definition.inputSchema, action);
|
|
773
|
+
const message = errors.join("; ");
|
|
774
|
+
return toolFailure("protocol", "invalid_input", message, message, {
|
|
775
|
+
recovery: `${message}; pass ${JSON.stringify(example)}`
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
return handler(db, input);
|
|
779
|
+
};
|
|
635
780
|
return definition;
|
|
636
781
|
}
|
|
637
782
|
function stringSchema(description, options = {}) {
|
|
@@ -3581,7 +3726,7 @@ var rewardWorkTool = defineQuestlogTool({
|
|
|
3581
3726
|
name: stringSchema("Reward name."),
|
|
3582
3727
|
now: integerSchema("Optional update timestamp for the update action.")
|
|
3583
3728
|
},
|
|
3584
|
-
[]
|
|
3729
|
+
["kind", "name"]
|
|
3585
3730
|
),
|
|
3586
3731
|
rewards: arraySchema(
|
|
3587
3732
|
objectSchema(
|
|
@@ -4408,7 +4553,7 @@ var shapeWorkTool = defineQuestlogTool({
|
|
|
4408
4553
|
title: stringSchema("Questline title."),
|
|
4409
4554
|
description: stringSchema("Optional questline description.")
|
|
4410
4555
|
},
|
|
4411
|
-
[]
|
|
4556
|
+
["title"]
|
|
4412
4557
|
),
|
|
4413
4558
|
rumorId: integerSchema("Rumor to settle, dismiss, or reopen."),
|
|
4414
4559
|
dismissedAt: integerSchema("Optional dismissal timestamp."),
|
|
@@ -4690,7 +4835,7 @@ var questlogSurfaceTools = questlogTools.map(
|
|
|
4690
4835
|
whenNotToUse: tool.whenNotToUse ?? "",
|
|
4691
4836
|
readOnly: tool.readOnly,
|
|
4692
4837
|
sideEffects: tool.sideEffects,
|
|
4693
|
-
inputSchema:
|
|
4838
|
+
inputSchema: tool.inputSchema,
|
|
4694
4839
|
handler: tool.handler
|
|
4695
4840
|
})
|
|
4696
4841
|
);
|
|
@@ -4725,47 +4870,6 @@ function isErrorResult(result) {
|
|
|
4725
4870
|
return typeof result === "object" && result !== null && "ok" in result && result.ok === false;
|
|
4726
4871
|
}
|
|
4727
4872
|
|
|
4728
|
-
// src/surfaces/validate_input.ts
|
|
4729
|
-
function validateInput(schema, input, path = "$") {
|
|
4730
|
-
const errors = [];
|
|
4731
|
-
const matchesType = (type) => {
|
|
4732
|
-
switch (type) {
|
|
4733
|
-
case "object":
|
|
4734
|
-
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
4735
|
-
case "array":
|
|
4736
|
-
return Array.isArray(input);
|
|
4737
|
-
case "integer":
|
|
4738
|
-
return typeof input === "number" && Number.isInteger(input);
|
|
4739
|
-
case "number":
|
|
4740
|
-
return typeof input === "number" && Number.isFinite(input);
|
|
4741
|
-
case "null":
|
|
4742
|
-
return input === null;
|
|
4743
|
-
default:
|
|
4744
|
-
return typeof input === type;
|
|
4745
|
-
}
|
|
4746
|
-
};
|
|
4747
|
-
if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
|
|
4748
|
-
return [`${path}: expected ${String(schema.type)}`];
|
|
4749
|
-
}
|
|
4750
|
-
if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
|
|
4751
|
-
errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
|
|
4752
|
-
if (schema.oneOf && !schema.oneOf.some((branch) => validateInput(branch, input, path).length === 0))
|
|
4753
|
-
errors.push(`${path}: must match at least one schema branch`);
|
|
4754
|
-
if (typeof input === "object" && input !== null && !Array.isArray(input)) {
|
|
4755
|
-
const record = input;
|
|
4756
|
-
for (const name of schema.required ?? [])
|
|
4757
|
-
if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
|
|
4758
|
-
for (const [name, property] of Object.entries(schema.properties ?? {}))
|
|
4759
|
-
if (Object.hasOwn(record, name))
|
|
4760
|
-
errors.push(...validateInput(property, record[name], `${path}.${name}`));
|
|
4761
|
-
}
|
|
4762
|
-
if (Array.isArray(input) && schema.items)
|
|
4763
|
-
input.forEach((value, index) => {
|
|
4764
|
-
errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
|
|
4765
|
-
});
|
|
4766
|
-
return errors;
|
|
4767
|
-
}
|
|
4768
|
-
|
|
4769
4873
|
// src/surfaces/mcp_server.ts
|
|
4770
4874
|
var MCP_LATEST_PROTOCOL_VERSION = "2026-07-28";
|
|
4771
4875
|
var MCP_SUPPORTED_PROTOCOL_VERSIONS = [
|
|
@@ -4865,7 +4969,15 @@ Not for: ${tool.whenNotToUse}` : ""),
|
|
|
4865
4969
|
const input = params.arguments === void 0 ? {} : params.arguments;
|
|
4866
4970
|
const errors = validateInput(tool.inputSchema, input);
|
|
4867
4971
|
if (errors.length)
|
|
4868
|
-
return result({
|
|
4972
|
+
return result({
|
|
4973
|
+
content: [
|
|
4974
|
+
{
|
|
4975
|
+
type: "text",
|
|
4976
|
+
text: `${errors.join("\n")}; pass ${JSON.stringify(minimalInput(tool.inputSchema, input?.action))}`
|
|
4977
|
+
}
|
|
4978
|
+
],
|
|
4979
|
+
isError: true
|
|
4980
|
+
});
|
|
4869
4981
|
try {
|
|
4870
4982
|
context ??= Promise.resolve().then(options.context);
|
|
4871
4983
|
const value = await tool.handler(await context, input);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { questlogMcpInstructions } from './chunk-SVWAEAKC.js';
|
|
3
|
+
import { questlogSkills } from './chunk-6KTQK3ZE.js';
|
|
4
|
+
import { reviewQuestlogTool, questlogSurfaceTools } from './chunk-UTUQPSGO.js';
|
|
5
|
+
import './chunk-QYSIJ2YN.js';
|
|
6
|
+
|
|
7
|
+
// src/soul.ts
|
|
8
|
+
var questlogSoulTraits = [
|
|
9
|
+
{
|
|
10
|
+
principle: "Store the least committed truth first.",
|
|
11
|
+
provenance: "The worst downstream errors usually start upstream: vague asks are turned into quests, soft ideas become fake deadlines, and half-understood work is treated as fully shaped. Using rumors and clarification before commitment keeps uncertainty where it belongs."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
principle: "Read before you prescribe.",
|
|
15
|
+
provenance: "Many management mistakes are category mistakes: blocked work gets treated as available, missed schedule as overdue, or resolved work as fully closed when follow-through still remains. Reading the derived state first prevents confident but wrong interventions."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
principle: "Protect history when reality changes.",
|
|
19
|
+
provenance: "Once execution starts, rewriting a quest into a different commitment destroys the meaning of the record. Honest finishes, abandonments, and follow-up quests preserve what actually happened and keep later review, planning, and reporting trustworthy."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
principle: "Close the last mile, not just the main work.",
|
|
23
|
+
provenance: "Operational debt often hides in almost-done states: work finished but not claimed, reported, handed off, reviewed, or retired. Treating closure as a real phase prevents stale rewards, lingering initiatives, and misleading progress signals."
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// src/surface/questlog_skill_spec.ts
|
|
28
|
+
var questlogSkillSpec = {
|
|
29
|
+
name: "questlog",
|
|
30
|
+
cheatSheet: [
|
|
31
|
+
"## Install",
|
|
32
|
+
"",
|
|
33
|
+
"Linux/macOS:",
|
|
34
|
+
"",
|
|
35
|
+
"```sh",
|
|
36
|
+
"curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh",
|
|
37
|
+
"```",
|
|
38
|
+
"",
|
|
39
|
+
"Installs `~/.local/bin/ghostpaw-questlog` after checking SHA256SUMS.",
|
|
40
|
+
"",
|
|
41
|
+
"Windows x64 (PowerShell):",
|
|
42
|
+
"",
|
|
43
|
+
"```powershell",
|
|
44
|
+
"irm https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.ps1 | iex",
|
|
45
|
+
"```",
|
|
46
|
+
"",
|
|
47
|
+
"Run tools as `ghostpaw-questlog ...`; use `~/.local/bin/ghostpaw-questlog` if it is not on PATH.",
|
|
48
|
+
"",
|
|
49
|
+
"`questlog` and `ghostpaw-questlog` are the same binary.",
|
|
50
|
+
"",
|
|
51
|
+
"- `questlog search <words>` before `add` to avoid duplicates.",
|
|
52
|
+
'- `ghostpaw-questlog add "..." --tag a,b --due tomorrow`',
|
|
53
|
+
`- \`questlog list [--view <view>]\`: ${reviewQuestlogTool.inputSchema.properties?.view?.enum?.join(", ")}.`,
|
|
54
|
+
'- `questlog done <id> --outcome "..."`',
|
|
55
|
+
"- `questlog search <words>`",
|
|
56
|
+
"- `questlog show <id>`",
|
|
57
|
+
"- Use `--json` on any plain command.",
|
|
58
|
+
"- Exit codes: 0 ok / 1 error / 2 usage / 3 needs input.",
|
|
59
|
+
"- Database: `~/.ghostpaw/questlog.db`; override with `--db` or `GHOSTPAW_QUESTLOG_DB`.",
|
|
60
|
+
"- Use one database per agent or project."
|
|
61
|
+
].join("\n"),
|
|
62
|
+
description: "Use the release binary ghostpaw-questlog to manage local tasks, calendar commitments, and recurring work. Use when planning, executing, reviewing, or organizing work.",
|
|
63
|
+
license: "MIT",
|
|
64
|
+
compatibility: "Release binary ghostpaw-questlog (no runtime needed); MCP stdio via ghostpaw-questlog mcp.",
|
|
65
|
+
bin: "ghostpaw-questlog",
|
|
66
|
+
packageName: "@ghostpaw/questlog",
|
|
67
|
+
server: "ghostpaw-questlog",
|
|
68
|
+
about: questlogMcpInstructions,
|
|
69
|
+
tools: questlogSurfaceTools,
|
|
70
|
+
workflows: questlogSkills,
|
|
71
|
+
principles: questlogSoulTraits.map((trait) => trait.principle)
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export { questlogSkillSpec };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { openQuestlogDb } from './chunk-3B6FMHZU.js';
|
|
3
3
|
import { questlogMcpInstructions } from './chunk-SVWAEAKC.js';
|
|
4
|
-
import {
|
|
5
|
-
import { questlogSurfaceTools } from './chunk-
|
|
4
|
+
import { isErrorResult, questlogVersion, resolveQuestlogDbPath } from './chunk-DKH623HU.js';
|
|
5
|
+
import { validateInput, questlogSurfaceTools } from './chunk-UTUQPSGO.js';
|
|
6
|
+
import { minimalInput } from './chunk-QYSIJ2YN.js';
|
|
6
7
|
|
|
7
8
|
// src/surfaces/mcp_server.ts
|
|
8
9
|
var MCP_LATEST_PROTOCOL_VERSION = "2026-07-28";
|
|
@@ -103,7 +104,15 @@ Not for: ${tool.whenNotToUse}` : ""),
|
|
|
103
104
|
const input = params.arguments === void 0 ? {} : params.arguments;
|
|
104
105
|
const errors = validateInput(tool.inputSchema, input);
|
|
105
106
|
if (errors.length)
|
|
106
|
-
return result({
|
|
107
|
+
return result({
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: `${errors.join("\n")}; pass ${JSON.stringify(minimalInput(tool.inputSchema, input?.action))}`
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
isError: true
|
|
115
|
+
});
|
|
107
116
|
try {
|
|
108
117
|
context ??= Promise.resolve().then(options.context);
|
|
109
118
|
const value = await tool.handler(await context, input);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { minimalInput } from './chunk-QYSIJ2YN.js';
|
|
3
|
+
|
|
2
4
|
// src/surfaces/skill_markdown.ts
|
|
3
5
|
function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
4
6
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(spec.name) || spec.name.length > 64)
|
|
@@ -26,7 +28,7 @@ function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
|
26
28
|
"",
|
|
27
29
|
`MCP: connect to ${spec.server}, then call a tool by name with its JSON arguments.`,
|
|
28
30
|
"",
|
|
29
|
-
`CLI: \`${spec.bin} call <tool> '<JSON object>'\` or \`${spec.bin} <tool> --parameter value
|
|
31
|
+
`CLI: \`${spec.bin} call <tool> '<JSON object>'\` or \`${spec.bin} <tool> --parameter value\`.`,
|
|
30
32
|
"",
|
|
31
33
|
`Inspect schemas with \`${spec.bin} describe <tool>\`. Use \`--db <path>\` to select a database.`,
|
|
32
34
|
""
|
|
@@ -46,17 +48,38 @@ function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
|
46
48
|
"| Parameter | Type | Required | Values / description |",
|
|
47
49
|
"| --- | --- | --- | --- |"
|
|
48
50
|
);
|
|
49
|
-
|
|
51
|
+
const rows = (schema, prefix = "") => {
|
|
52
|
+
const properties = { ...schema.properties };
|
|
53
|
+
const required = new Set(schema.required);
|
|
54
|
+
for (const branch of schema.oneOf ?? []) {
|
|
55
|
+
for (const [key, value] of Object.entries(branch.properties ?? {}))
|
|
56
|
+
properties[key] ??= value;
|
|
57
|
+
for (const key of branch.required ?? []) required.add(key);
|
|
58
|
+
}
|
|
59
|
+
for (const [name, property] of Object.entries(properties)) {
|
|
60
|
+
if (prefix && Object.keys(properties).length > 8 && !required.has(name)) continue;
|
|
61
|
+
const path = `${prefix}${name}`;
|
|
62
|
+
lines.push(
|
|
63
|
+
`| ${path} | ${property.type ?? property.oneOf?.map((branch) => branch.type).join(" / ") ?? "any"} | ${required.has(name) ? "yes" : "no"} | ${((property.enum ? `${property.enum.join(", ")}. ` : "") + (property.description ?? "")).replaceAll("|", "\\|").replaceAll("\n", " ")} |`
|
|
64
|
+
);
|
|
65
|
+
if (property.properties || property.oneOf) rows(property, `${path}.`);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
rows(tool.inputSchema);
|
|
69
|
+
lines.push("", "```sh");
|
|
70
|
+
for (const action of tool.inputSchema.properties?.action?.enum?.slice(0, 3) ?? [void 0]) {
|
|
50
71
|
lines.push(
|
|
51
|
-
|
|
72
|
+
`${spec.bin} call ${tool.name} '${JSON.stringify(minimalInput(tool.inputSchema, action))}'`
|
|
52
73
|
);
|
|
74
|
+
}
|
|
75
|
+
lines.push("```");
|
|
53
76
|
lines.push("");
|
|
54
77
|
}
|
|
55
78
|
lines.push(
|
|
56
79
|
"## Workflow guides",
|
|
57
80
|
"",
|
|
58
81
|
...spec.workflows.map(
|
|
59
|
-
(workflow) => `- [${workflow.name}](${referencesBase}/${workflow.name}.md): ${workflow.description}`
|
|
82
|
+
(workflow) => `- \`${spec.bin} skill ${workflow.name}\` ([${workflow.name}](${referencesBase}/${workflow.name}.md)): ${workflow.description}`
|
|
60
83
|
),
|
|
61
84
|
"",
|
|
62
85
|
"## Principles",
|
|
@@ -65,7 +88,12 @@ function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
|
65
88
|
""
|
|
66
89
|
);
|
|
67
90
|
const output = lines.join("\n");
|
|
68
|
-
|
|
91
|
+
const fallback = spec.packageName ? `
|
|
92
|
+
## Without the binary
|
|
93
|
+
|
|
94
|
+
Use \`npx -y ${spec.packageName} ...\` in npm-based environments (Node 24+). Harnesses that embed it in code can import \`${spec.packageName}\` as a library.
|
|
95
|
+
` : "";
|
|
96
|
+
if (!spec.cheatSheet) return output + fallback;
|
|
69
97
|
const title = `# ${spec.name}
|
|
70
98
|
|
|
71
99
|
`;
|
|
@@ -74,7 +102,7 @@ function renderSkillMarkdown(spec, { referencesBase = "references" } = {}) {
|
|
|
74
102
|
|
|
75
103
|
## Appendix: MCP and tool calls
|
|
76
104
|
|
|
77
|
-
${output.slice(start).replace(/^## /gm, "### ")}`;
|
|
105
|
+
${output.slice(start).replace(/^## /gm, "### ")}${fallback}`;
|
|
78
106
|
}
|
|
79
107
|
|
|
80
108
|
export { renderSkillMarkdown };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostpaw/questlog",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Unified task and calendar model for Node.js — SQLite, zero dependencies, with a built-in LLM tool facade",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"devDependencies": {
|
|
128
128
|
"@biomejs/biome": "2.4.4",
|
|
129
129
|
"@types/node": "^25.3.0",
|
|
130
|
-
"esbuild": "^0.
|
|
130
|
+
"esbuild": "^0.28.2",
|
|
131
131
|
"fflate": "0.8.3",
|
|
132
132
|
"preact": "^10.29.0",
|
|
133
133
|
"sql.js-fts5": "^1.4.0",
|
|
@@ -138,5 +138,8 @@
|
|
|
138
138
|
"ghostpaw-questlog": "./dist/cli.js",
|
|
139
139
|
"questlog": "./dist/cli.js"
|
|
140
140
|
},
|
|
141
|
-
"mcpName": "io.github.GhostPawJS/questlog"
|
|
141
|
+
"mcpName": "io.github.GhostPawJS/questlog",
|
|
142
|
+
"overrides": {
|
|
143
|
+
"esbuild": "$esbuild"
|
|
144
|
+
}
|
|
142
145
|
}
|