@ghostpaw/questlog 0.7.0 → 0.8.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 CHANGED
@@ -81,7 +81,7 @@ ghostpaw-questlog list --view quests.resolved --json
81
81
  `list` defaults to available quests; `list --help` lists all supported views.
82
82
  Its `--limit` caps text output; JSON preserves the full review tool result.
83
83
  `search --limit` caps matches in both formats. `show` inspects a quest id.
84
- `done` requires `--outcome`, the written result stored with the finished quest.
84
+ `done` stores `--outcome` with the finished quest; without it the command asks for one and exits 3.
85
85
 
86
86
  Plain commands print short text by default. Use `--json` for the full tool result
87
87
  and `--compact` for compact JSON. `--db path` works before or after the command.
@@ -110,11 +110,79 @@ npx -y @ghostpaw/questlog skill > SKILL.md
110
110
 
111
111
  ## Install
112
112
 
113
- ```bash
114
- npm install @ghostpaw/questlog
113
+ The [npm package](https://www.npmjs.com/package/@ghostpaw/questlog) requires Node 24+:
114
+
115
+ ```sh
116
+ npm install -g @ghostpaw/questlog
117
+ npx -y @ghostpaw/questlog --help
118
+ ```
119
+
120
+ As a library dependency: `npm install @ghostpaw/questlog`. It uses the built-in
121
+ `node:sqlite` module, so there are no runtime dependencies.
122
+
123
+ Standalone binaries are available from [GitHub Releases](https://github.com/GhostPawJS/questlog/releases)
124
+ for linux-x64, linux-arm64, darwin-arm64, darwin-x64 and windows-x64.
125
+
126
+ ```sh
127
+ curl -fsSL https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.sh | sh
128
+ ```
129
+
130
+ ```powershell
131
+ irm https://raw.githubusercontent.com/GhostPawJS/questlog/main/install.ps1 | iex
132
+ ```
133
+
134
+ Other release installers:
135
+
136
+ ```sh
137
+ mise use -g github:GhostPawJS/questlog
138
+ ubi --project GhostPawJS/questlog --exe ghostpaw-questlog --in ~/.local/bin
139
+ eget GhostPawJS/questlog
140
+ ```
141
+
142
+ For [aqua](https://aquaproj.github.io/docs/reference/registry-config/), define a
143
+ `github_release` package in `aqua.yaml`:
144
+
145
+ ```yaml
146
+ registries:
147
+ - name: questlog
148
+ type: local
149
+ path: questlog-registry.yaml
150
+ packages:
151
+ - name: GhostPawJS/questlog@v0.8.0
152
+ registry: questlog
153
+ ```
154
+
155
+ `questlog-registry.yaml`:
156
+
157
+ ```yaml
158
+ packages:
159
+ - type: github_release
160
+ repo_owner: GhostPawJS
161
+ repo_name: questlog
162
+ asset: ghostpaw-questlog-{{trimV .Version}}-{{.OS}}-{{.Arch}}.tar.gz
163
+ format: tar.gz
164
+ replacements: { amd64: x64 }
165
+ overrides:
166
+ - goos: windows
167
+ asset: ghostpaw-questlog-{{trimV .Version}}-windows-{{.Arch}}.zip
168
+ format: zip
169
+ files:
170
+ - name: ghostpaw-questlog
171
+ ```
172
+
173
+ Install scripts verify SHA256SUMS. To verify a downloaded archive's
174
+ [build attestation](https://cli.github.com/manual/gh_attestation_verify):
175
+
176
+ ```sh
177
+ gh attestation verify <archive> -R GhostPawJS/questlog
115
178
  ```
116
179
 
117
- Requires **Node.js 24+** (uses the built-in `node:sqlite` module).
180
+ Set `GHOSTPAW_VERIFY=attestation` for attestation verification in `install.sh`.
181
+ Binaries are unsigned; macOS binaries carry an ad-hoc signature. For a browser
182
+ download on macOS, remove quarantine with
183
+ `xattr -d com.apple.quarantine /path/to/ghostpaw-questlog`.
184
+ Linux binaries require glibc 2.28+; use npx on Alpine.
185
+ See the [binary build workflow](.github/workflows/release-binaries.yml).
118
186
 
119
187
  ## Quick Start
120
188
 
package/dist/cli.js CHANGED
@@ -13,6 +13,14 @@ var __export = (target, all) => {
13
13
  __defProp(target, name, { get: all[name], enumerable: true });
14
14
  };
15
15
 
16
+ // src/version.ts
17
+ var questlogVersion;
18
+ var init_version = __esm({
19
+ "src/version.ts"() {
20
+ questlogVersion = "0.8.0";
21
+ }
22
+ });
23
+
16
24
  // src/questlines/map_questline_row.ts
17
25
  function mapQuestlineRow(row) {
18
26
  return {
@@ -3935,6 +3943,16 @@ var init_reward_work_tool = __esm({
3935
3943
  function runQuestToolHandler(db, input) {
3936
3944
  try {
3937
3945
  const current = getQuestDetail(db, input.questId);
3946
+ if (input.action !== "start" && input.action !== "log_effort") {
3947
+ const outcome = input.outcome;
3948
+ if (typeof outcome !== "string") {
3949
+ return toolNeedsClarification(
3950
+ "missing_required_choice",
3951
+ `What outcome should be recorded for quest \`${current.title}\`?`,
3952
+ ["outcome"]
3953
+ );
3954
+ }
3955
+ }
3938
3956
  switch (input.action) {
3939
3957
  case "start": {
3940
3958
  if (current.resolvedAt != null) {
@@ -5173,68 +5191,6 @@ var init_questlog_surface_tools = __esm({
5173
5191
  }
5174
5192
  });
5175
5193
 
5176
- // src/surfaces/surface_types.ts
5177
- function isErrorResult(result) {
5178
- return typeof result === "object" && result !== null && "ok" in result && result.ok === false;
5179
- }
5180
- var init_surface_types = __esm({
5181
- "src/surfaces/surface_types.ts"() {
5182
- }
5183
- });
5184
-
5185
- // src/surfaces/validate_input.ts
5186
- function validateInput(schema, input, path = "$") {
5187
- const errors = [];
5188
- const matchesType = (type) => {
5189
- switch (type) {
5190
- case "object":
5191
- return typeof input === "object" && input !== null && !Array.isArray(input);
5192
- case "array":
5193
- return Array.isArray(input);
5194
- case "integer":
5195
- return typeof input === "number" && Number.isInteger(input);
5196
- case "number":
5197
- return typeof input === "number" && Number.isFinite(input);
5198
- case "null":
5199
- return input === null;
5200
- default:
5201
- return typeof input === type;
5202
- }
5203
- };
5204
- if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
5205
- return [`${path}: expected ${String(schema.type)}`];
5206
- }
5207
- if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
5208
- errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
5209
- if (schema.oneOf && !schema.oneOf.some((branch) => validateInput(branch, input, path).length === 0))
5210
- errors.push(`${path}: must match at least one schema branch`);
5211
- if (typeof input === "object" && input !== null && !Array.isArray(input)) {
5212
- const record = input;
5213
- for (const name of schema.required ?? [])
5214
- if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
5215
- for (const [name, property] of Object.entries(schema.properties ?? {}))
5216
- if (Object.hasOwn(record, name))
5217
- errors.push(...validateInput(property, record[name], `${path}.${name}`));
5218
- }
5219
- if (Array.isArray(input) && schema.items)
5220
- input.forEach((value, index) => {
5221
- errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
5222
- });
5223
- return errors;
5224
- }
5225
- var init_validate_input = __esm({
5226
- "src/surfaces/validate_input.ts"() {
5227
- }
5228
- });
5229
-
5230
- // src/version.ts
5231
- var questlogVersion;
5232
- var init_version = __esm({
5233
- "src/version.ts"() {
5234
- questlogVersion = "0.7.0";
5235
- }
5236
- });
5237
-
5238
5194
  // src/questlines/init_questline_tables.ts
5239
5195
  function initQuestlineTables(db) {
5240
5196
  db.exec(`
@@ -5685,6 +5641,60 @@ var init_resolve_questlog_db_path = __esm({
5685
5641
  }
5686
5642
  });
5687
5643
 
5644
+ // src/surfaces/surface_types.ts
5645
+ function isErrorResult(result) {
5646
+ return typeof result === "object" && result !== null && "ok" in result && result.ok === false;
5647
+ }
5648
+ var init_surface_types = __esm({
5649
+ "src/surfaces/surface_types.ts"() {
5650
+ }
5651
+ });
5652
+
5653
+ // src/surfaces/validate_input.ts
5654
+ function validateInput(schema, input, path = "$") {
5655
+ const errors = [];
5656
+ const matchesType = (type) => {
5657
+ switch (type) {
5658
+ case "object":
5659
+ return typeof input === "object" && input !== null && !Array.isArray(input);
5660
+ case "array":
5661
+ return Array.isArray(input);
5662
+ case "integer":
5663
+ return typeof input === "number" && Number.isInteger(input);
5664
+ case "number":
5665
+ return typeof input === "number" && Number.isFinite(input);
5666
+ case "null":
5667
+ return input === null;
5668
+ default:
5669
+ return typeof input === type;
5670
+ }
5671
+ };
5672
+ if (schema.type && !(Array.isArray(schema.type) ? schema.type : [schema.type]).some(matchesType)) {
5673
+ return [`${path}: expected ${String(schema.type)}`];
5674
+ }
5675
+ if (schema.enum && !schema.enum.some((value) => JSON.stringify(value) === JSON.stringify(input)))
5676
+ errors.push(`${path}: expected one of ${JSON.stringify(schema.enum)}`);
5677
+ if (schema.oneOf && !schema.oneOf.some((branch) => validateInput(branch, input, path).length === 0))
5678
+ errors.push(`${path}: must match at least one schema branch`);
5679
+ if (typeof input === "object" && input !== null && !Array.isArray(input)) {
5680
+ const record = input;
5681
+ for (const name of schema.required ?? [])
5682
+ if (!Object.hasOwn(record, name)) errors.push(`${path}.${name}: required`);
5683
+ for (const [name, property] of Object.entries(schema.properties ?? {}))
5684
+ if (Object.hasOwn(record, name))
5685
+ errors.push(...validateInput(property, record[name], `${path}.${name}`));
5686
+ }
5687
+ if (Array.isArray(input) && schema.items)
5688
+ input.forEach((value, index) => {
5689
+ errors.push(...validateInput(schema.items, value, `${path}[${index}]`));
5690
+ });
5691
+ return errors;
5692
+ }
5693
+ var init_validate_input = __esm({
5694
+ "src/surfaces/validate_input.ts"() {
5695
+ }
5696
+ });
5697
+
5688
5698
  // src/surfaces/mcp_server.ts
5689
5699
  function createMcpServer(options) {
5690
5700
  let initialized = false;
@@ -6995,6 +7005,9 @@ var init_questlog_skill_spec = __esm({
6995
7005
  };
6996
7006
  }
6997
7007
  });
7008
+
7009
+ // src/surface/questlog_cli_options.ts
7010
+ init_version();
6998
7011
  var CliUsageError = class extends Error {
6999
7012
  exitCode = 2;
7000
7013
  };
@@ -7117,8 +7130,10 @@ function renderQuestlogPlainResult(result, db, values) {
7117
7130
  ].filter((v) => v != null).join(" ").replace(/[\r\n]+/g, " ");
7118
7131
  };
7119
7132
  if (!r.ok)
7120
- return `${r.summary}
7121
- ${r.outcome === "needs_clarification" ? r.clarification.question : r.error.message}
7133
+ return r.outcome === "needs_clarification" ? `${r.clarification.question}
7134
+ Missing: ${r.clarification.missing.map((name) => `--${name}`).join(", ")}
7135
+ ` : `${r.summary}
7136
+ ${r.error.message}
7122
7137
  `;
7123
7138
  if (r.data.items) {
7124
7139
  const items = values.limit === void 0 ? r.data.items : r.data.items.slice(0, Math.max(0, Number(values.limit)));
@@ -7195,8 +7210,7 @@ function questlogPlainCommands() {
7195
7210
  {
7196
7211
  name: "outcome",
7197
7212
  type: "string",
7198
- required: true,
7199
- description: "What the finished quest produced."
7213
+ description: "What the finished quest produced; asked for when omitted."
7200
7214
  }
7201
7215
  ]
7202
7216
  },
@@ -7204,7 +7218,7 @@ function questlogPlainCommands() {
7204
7218
  input: (v) => ({
7205
7219
  action: "finish",
7206
7220
  questId: v.id,
7207
- outcome: v.outcome
7221
+ ...v.outcome === void 0 ? {} : { outcome: v.outcome }
7208
7222
  }),
7209
7223
  render: renderQuestlogPlainResult
7210
7224
  },
@@ -7240,8 +7254,34 @@ function questlogPlainCommands() {
7240
7254
  }));
7241
7255
  }
7242
7256
 
7243
- // src/cli.ts
7257
+ // src/surface/questlog_cli_options.ts
7244
7258
  init_questlog_surface_tools();
7259
+ var questlogCliOptions = {
7260
+ bin: "ghostpaw-questlog",
7261
+ version: questlogVersion,
7262
+ description: "Local task and calendar library",
7263
+ tools: questlogSurfaceTools,
7264
+ openContext: async (options) => {
7265
+ const { openQuestlogDb: openQuestlogDb2 } = await Promise.resolve().then(() => (init_open_questlog_db(), open_questlog_db_exports));
7266
+ const { resolveQuestlogDbPath: resolveQuestlogDbPath2 } = await Promise.resolve().then(() => (init_resolve_questlog_db_path(), resolve_questlog_db_path_exports));
7267
+ return openQuestlogDb2(
7268
+ resolveQuestlogDbPath2(options.db === void 0 ? {} : { flag: options.db })
7269
+ );
7270
+ },
7271
+ closeContext: (db) => db.close(),
7272
+ commands: {
7273
+ plain: questlogPlainCommands(),
7274
+ mcp: async (options) => {
7275
+ const { serveQuestlogMcp: serveQuestlogMcp2 } = await Promise.resolve().then(() => (init_serve_questlog_mcp(), serve_questlog_mcp_exports));
7276
+ await serveQuestlogMcp2(options.db === void 0 ? {} : { dbPath: options.db });
7277
+ },
7278
+ skill: async () => {
7279
+ const { renderSkillMarkdown: renderSkillMarkdown2 } = await Promise.resolve().then(() => (init_skill_markdown(), skill_markdown_exports));
7280
+ const { questlogSkillSpec: questlogSkillSpec2 } = await Promise.resolve().then(() => (init_questlog_skill_spec(), questlog_skill_spec_exports));
7281
+ return renderSkillMarkdown2(questlogSkillSpec2);
7282
+ }
7283
+ }
7284
+ };
7245
7285
 
7246
7286
  // src/surfaces/cli.ts
7247
7287
  init_surface_types();
@@ -7445,30 +7485,4 @@ ${JSON.stringify(tool.inputSchema, null, 2)}
7445
7485
  }
7446
7486
 
7447
7487
  // src/cli.ts
7448
- init_version();
7449
- process.exitCode = await runToolCli(process.argv.slice(2), {
7450
- bin: "ghostpaw-questlog",
7451
- version: questlogVersion,
7452
- description: "Local task and calendar library",
7453
- tools: questlogSurfaceTools,
7454
- openContext: async (options) => {
7455
- const { openQuestlogDb: openQuestlogDb2 } = await Promise.resolve().then(() => (init_open_questlog_db(), open_questlog_db_exports));
7456
- const { resolveQuestlogDbPath: resolveQuestlogDbPath2 } = await Promise.resolve().then(() => (init_resolve_questlog_db_path(), resolve_questlog_db_path_exports));
7457
- return openQuestlogDb2(
7458
- resolveQuestlogDbPath2(options.db === void 0 ? {} : { flag: options.db })
7459
- );
7460
- },
7461
- closeContext: (db) => db.close(),
7462
- commands: {
7463
- plain: questlogPlainCommands(),
7464
- mcp: async (options) => {
7465
- const { serveQuestlogMcp: serveQuestlogMcp2 } = await Promise.resolve().then(() => (init_serve_questlog_mcp(), serve_questlog_mcp_exports));
7466
- await serveQuestlogMcp2(options.db === void 0 ? {} : { dbPath: options.db });
7467
- },
7468
- skill: async () => {
7469
- const { renderSkillMarkdown: renderSkillMarkdown2 } = await Promise.resolve().then(() => (init_skill_markdown(), skill_markdown_exports));
7470
- const { questlogSkillSpec: questlogSkillSpec2 } = await Promise.resolve().then(() => (init_questlog_skill_spec(), questlog_skill_spec_exports));
7471
- return renderSkillMarkdown2(questlogSkillSpec2);
7472
- }
7473
- }
7474
- });
7488
+ process.exitCode = await runToolCli(process.argv.slice(2), questlogCliOptions);
package/dist/index.cjs CHANGED
@@ -4743,6 +4743,16 @@ var rewardWorkTool = defineQuestlogTool({
4743
4743
  function runQuestToolHandler(db, input) {
4744
4744
  try {
4745
4745
  const current = getQuestDetail(db, input.questId);
4746
+ if (input.action !== "start" && input.action !== "log_effort") {
4747
+ const outcome = input.outcome;
4748
+ if (typeof outcome !== "string") {
4749
+ return toolNeedsClarification(
4750
+ "missing_required_choice",
4751
+ `What outcome should be recorded for quest \`${current.title}\`?`,
4752
+ ["outcome"]
4753
+ );
4754
+ }
4755
+ }
4746
4756
  switch (input.action) {
4747
4757
  case "start": {
4748
4758
  if (current.resolvedAt != null) {
package/dist/index.js CHANGED
@@ -4741,6 +4741,16 @@ var rewardWorkTool = defineQuestlogTool({
4741
4741
  function runQuestToolHandler(db, input) {
4742
4742
  try {
4743
4743
  const current = getQuestDetail(db, input.questId);
4744
+ if (input.action !== "start" && input.action !== "log_effort") {
4745
+ const outcome = input.outcome;
4746
+ if (typeof outcome !== "string") {
4747
+ return toolNeedsClarification(
4748
+ "missing_required_choice",
4749
+ `What outcome should be recorded for quest \`${current.title}\`?`,
4750
+ ["outcome"]
4751
+ );
4752
+ }
4753
+ }
4744
4754
  switch (input.action) {
4745
4755
  case "start": {
4746
4756
  if (current.resolvedAt != null) {
@@ -677,7 +677,7 @@ var init_open_questlog_db = __esm({
677
677
  var questlogVersion;
678
678
  var init_version = __esm({
679
679
  "src/version.ts"() {
680
- questlogVersion = "0.7.0";
680
+ questlogVersion = "0.8.0";
681
681
  }
682
682
  });
683
683
 
@@ -4611,6 +4611,16 @@ var init_reward_work_tool = __esm({
4611
4611
  function runQuestToolHandler(db, input) {
4612
4612
  try {
4613
4613
  const current = getQuestDetail(db, input.questId);
4614
+ if (input.action !== "start" && input.action !== "log_effort") {
4615
+ const outcome = input.outcome;
4616
+ if (typeof outcome !== "string") {
4617
+ return toolNeedsClarification(
4618
+ "missing_required_choice",
4619
+ `What outcome should be recorded for quest \`${current.title}\`?`,
4620
+ ["outcome"]
4621
+ );
4622
+ }
4623
+ }
4614
4624
  switch (input.action) {
4615
4625
  case "start": {
4616
4626
  if (current.resolvedAt != null) {
package/dist/mcp.cjs CHANGED
@@ -386,7 +386,7 @@ async function openQuestlogDb(path) {
386
386
  }
387
387
 
388
388
  // src/version.ts
389
- var questlogVersion = "0.7.0";
389
+ var questlogVersion = "0.8.0";
390
390
 
391
391
  // src/surface/questlog_mcp_instructions.ts
392
392
  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.";
@@ -3599,6 +3599,16 @@ var rewardWorkTool = defineQuestlogTool({
3599
3599
  function runQuestToolHandler(db, input) {
3600
3600
  try {
3601
3601
  const current = getQuestDetail(db, input.questId);
3602
+ if (input.action !== "start" && input.action !== "log_effort") {
3603
+ const outcome = input.outcome;
3604
+ if (typeof outcome !== "string") {
3605
+ return toolNeedsClarification(
3606
+ "missing_required_choice",
3607
+ `What outcome should be recorded for quest \`${current.title}\`?`,
3608
+ ["outcome"]
3609
+ );
3610
+ }
3611
+ }
3602
3612
  switch (input.action) {
3603
3613
  case "start": {
3604
3614
  if (current.resolvedAt != null) {
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.7.0";
387
+ var questlogVersion = "0.8.0";
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.";
@@ -3597,6 +3597,16 @@ var rewardWorkTool = defineQuestlogTool({
3597
3597
  function runQuestToolHandler(db, input) {
3598
3598
  try {
3599
3599
  const current = getQuestDetail(db, input.questId);
3600
+ if (input.action !== "start" && input.action !== "log_effort") {
3601
+ const outcome = input.outcome;
3602
+ if (typeof outcome !== "string") {
3603
+ return toolNeedsClarification(
3604
+ "missing_required_choice",
3605
+ `What outcome should be recorded for quest \`${current.title}\`?`,
3606
+ ["outcome"]
3607
+ );
3608
+ }
3609
+ }
3600
3610
  switch (input.action) {
3601
3611
  case "start": {
3602
3612
  if (current.resolvedAt != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostpaw/questlog",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
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": {
@@ -65,7 +65,10 @@
65
65
  "check:api": "node scripts/guard/api.mjs",
66
66
  "check:consumer": "node scripts/guard/consumer.mjs",
67
67
  "check:startup": "node scripts/guard/startup.mjs",
68
- "mcpb": "node scripts/mcpb/build.mjs"
68
+ "mcpb": "node scripts/mcpb/build.mjs",
69
+ "sea": "node scripts/sea/build.mjs",
70
+ "sea:smoke": "node scripts/sea/smoke.mjs",
71
+ "sea:bench": "node scripts/sea/bench.mjs"
69
72
  },
70
73
  "engines": {
71
74
  "node": ">=24"