@davesheffer/hunch 1.33.0 → 1.36.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.
Files changed (40) hide show
  1. package/README.md +9 -1
  2. package/dist/cli/index.js +55 -7
  3. package/dist/cli/invocation.d.ts +8 -0
  4. package/dist/cli/invocation.js +17 -10
  5. package/dist/cli/taskReport.js +52 -4
  6. package/dist/cli/update.js +5 -5
  7. package/dist/client/state.d.ts +4 -4
  8. package/dist/constitution/schema.d.ts +12 -12
  9. package/dist/core/spawnCommand.d.ts +14 -0
  10. package/dist/core/spawnCommand.js +61 -0
  11. package/dist/core/stateContract.d.ts +3 -3
  12. package/dist/core/taskDelivery.d.ts +15 -0
  13. package/dist/core/taskDelivery.js +38 -0
  14. package/dist/core/taskRecord.d.ts +39 -0
  15. package/dist/core/taskRecord.js +185 -0
  16. package/dist/core/taskReport.d.ts +8 -1
  17. package/dist/core/taskReport.js +28 -14
  18. package/dist/core/taskReportEvidence.js +18 -3
  19. package/dist/core/taskReportHook.d.ts +18 -3
  20. package/dist/core/taskReportHook.js +82 -17
  21. package/dist/core/taskReportPaths.d.ts +6 -0
  22. package/dist/core/taskReportPaths.js +13 -0
  23. package/dist/core/types.d.ts +176 -1
  24. package/dist/core/types.js +40 -1
  25. package/dist/core/updatecheck.d.ts +51 -0
  26. package/dist/core/updatecheck.js +266 -0
  27. package/dist/core/version.d.ts +2 -0
  28. package/dist/core/version.js +3 -1
  29. package/dist/integrations/claudemd.js +1 -1
  30. package/dist/integrations/gitignore.js +1 -0
  31. package/dist/integrations/health.js +27 -2
  32. package/dist/mcp/server.js +11 -2
  33. package/dist/mcp/taskReportTools.d.ts +4 -4
  34. package/dist/mcp/taskReportTools.js +34 -8
  35. package/dist/store/hunchStore.d.ts +5 -1
  36. package/dist/store/hunchStore.js +18 -0
  37. package/dist/taskReports.d.ts +1 -1
  38. package/dist/taskReports.js +16 -4
  39. package/package.json +1 -1
  40. package/server.json +2 -2
@@ -164,14 +164,39 @@ export function inspectIntegrations(root, selected) {
164
164
  continue;
165
165
  const capabilities = Object.fromEntries(CAPABILITIES.map(c => [c, { status: "untested", detail: "No runtime evidence" }]));
166
166
  report.harnesses.push({ harness, capabilities });
167
+ const mcpPath = join(root, spec.mcp);
168
+ const hooksFileExists = Boolean(spec.hooks && existsSync(join(root, spec.hooks)));
169
+ let mcpEntryAbsent = false;
170
+ try {
171
+ lstatSync(mcpPath);
172
+ }
173
+ catch (e) {
174
+ mcpEntryAbsent = e.code === "ENOENT";
175
+ }
167
176
  try {
168
177
  const launcher = readLauncher(root, harness);
169
178
  recordPins(spec.mcp, [launcher.command, ...launcher.args]);
170
179
  capabilities.mcp.detail = "Configured locally; use --probe to verify a fresh server, then reconnect the host";
171
180
  }
172
181
  catch (e) {
173
- report.issues.push({ file: spec.mcp, code: "mcp-config", detail: e.message });
174
- capabilities.mcp.detail = "MCP configuration missing, disabled, invalid, or outside supported inspection format";
182
+ // A harness can be detected here via its hooks file alone —
183
+ // some hooks files are deliberately committed while their MCP config is
184
+ // a per-clone, gitignored scaffold (e.g. this repo's own
185
+ // .windsurf/hooks.json). On a fresh checkout that config simply doesn't
186
+ // exist yet, which is a "not configured on this machine" state, not a
187
+ // repository-level misconfiguration — it must stay `untested`
188
+ // (informational, matching every other not-yet-evidenced capability
189
+ // here), not a hard `issues` entry that fails `hunch doctor` on every
190
+ // clone forever. A file that EXISTS but is malformed/disabled/
191
+ // unreadable in some other way is still a genuine issue.
192
+ // lstat distinguishes a truly absent per-machine file from a dangling
193
+ // symlink. The latter is a broken configuration and must remain loud.
194
+ const notConfiguredHere = !selected && hooksFileExists && mcpEntryAbsent && e.code === "ENOENT";
195
+ if (!notConfiguredHere)
196
+ report.issues.push({ file: spec.mcp, code: "mcp-config", detail: e.message });
197
+ capabilities.mcp.detail = notConfiguredHere
198
+ ? "Not configured on this machine — a hooks file exists, but no local MCP config exists yet; run `hunch init` or set up this host"
199
+ : "MCP configuration disabled, invalid, or outside supported inspection format";
175
200
  }
176
201
  let events = {};
177
202
  let disabled = false;
@@ -32,6 +32,7 @@ import { withWriteLock } from "../serve/writelock.js";
32
32
  import { advertisedTeamRemoteContract, ensureTeamOverlay, overlayMatchesTeamRemote, readTeamConfig, teamRemoteContract, teamSharedRef } from "../integrations/team.js";
33
33
  import { formatSearchHit, formatStructure } from "../core/format.js";
34
34
  import { isStateKind, stateSupplements } from "../core/stateDelivery.js";
35
+ import { taskSupplements } from "../core/taskDelivery.js";
35
36
  import { diagnoseIssueCorrectionStage, formatCorrectionStageDiagnostic } from "../core/correctionStage.js";
36
37
  import { compileVerifiedEvidenceMap, EvidenceExecutionSchema, EvidenceInterventionSchema, EvidenceProbeSchema, formatVerifiedEvidenceMap, VerifiedEvidenceReceiptSchema, } from "../core/evidenceMap.js";
37
38
  import { collectCorrectionStageSources } from "../extractors/correctionSources.js";
@@ -845,6 +846,10 @@ export function buildServerWithRootControl(initialRoot, options = {}) {
845
846
  parts.push(`\nCOMPONENTS: ${w.components.map((c) => `${c.name} (${c.id})`).join(", ")}`);
846
847
  if (w.symbols.length)
847
848
  parts.push(`\nSYMBOLS: ${w.symbols.slice(0, WHY_CAP * 2).map((s) => `${s.name} [fan-in ${s.metrics.fan_in}, churn ${s.metrics.churn_90d}]`).join(", ")}${more(w.symbols.length, WHY_CAP * 2)}`);
849
+ const recentTasks = store.tasksFor(target, 5);
850
+ if (recentTasks.length) {
851
+ parts.push(`\nRECENT TASKS (agent work that touched this):\n${recentTasks.map((t) => ` • ${t.id} ${t.finished_at.slice(0, 10)} ${t.title} — ${t.lessons.length} lesson(s), ${t.applied.length} applied, ${t.saved.length} saved${t.conformance.some((c) => c.outcome === "violated") ? ", rule VIOLATED" : ""}`).join("\n")}`);
852
+ }
848
853
  if (parts.length === 1)
849
854
  parts.push("\n(No recorded decisions/bugs/constraints yet for this target.)");
850
855
  return ok(parts.join("\n"));
@@ -1071,7 +1076,7 @@ export function buildServerWithRootControl(initialRoot, options = {}) {
1071
1076
  const records = as_of ? [] : snapshotDeliveredRecords(store, envelope);
1072
1077
  // First delivery of a revision in this task earns one line; repeats stay quiet.
1073
1078
  const recalled = renderRecalledLine(unseenLessons(root, task_id, records));
1074
- const occurrence = recordTaskDelivery(root, task_id, envelope, records);
1079
+ const occurrence = recordTaskDelivery(root, task_id, envelope, records, undefined, target);
1075
1080
  result.content.push({ type: "text", text: `${recalled ? `${recalled}\n` : ""}Task evidence: ${task_id} · occurrence ${occurrence}.\n${records.slice(0, 20).map(r => `${r.record_id} @ ${r.content_hash}`).join("\n")}${records.length > 20 ? "\nMore record identities: hunch_report(task_id)." : ""}` });
1076
1081
  }
1077
1082
  catch {
@@ -1097,6 +1102,9 @@ export function buildServerWithRootControl(initialRoot, options = {}) {
1097
1102
  // latest receipts whose subject/text matches the target — bounded, ordered, sharing the
1098
1103
  // brief's budget as supplements. Withheld on time-travel: state records carry no as-of view.
1099
1104
  const stateGrounding = asOf ? [] : stateSupplements(store.stateSlice(target), target);
1105
+ // Recent finished tasks that touched the target: what earlier agent work did
1106
+ // here, from graph memory. Advisory history sharing the brief's budget.
1107
+ const recentTasks = asOf ? [] : taskSupplements(store.tasksFor(target, 3), target);
1100
1108
  const options = {
1101
1109
  root,
1102
1110
  symbols: store.recs("symbols"),
@@ -1104,7 +1112,7 @@ export function buildServerWithRootControl(initialRoot, options = {}) {
1104
1112
  decisionCorpus: store.recs("decisions"),
1105
1113
  historical: !!asOf,
1106
1114
  profile: profile ?? "builder",
1107
- supplements: [...(dnaSupplement ? [dnaSupplement] : []), ...stateGrounding, ...(asOf ? [] : conventionSupplements(store.recs("conventions")))],
1115
+ supplements: [...(dnaSupplement ? [dnaSupplement] : []), ...stateGrounding, ...recentTasks, ...(asOf ? [] : conventionSupplements(store.recs("conventions")))],
1108
1116
  };
1109
1117
  // Task-phrase input ("improve retrieval ranking") resolves no file/symbol and
1110
1118
  // used to return an empty brief while the graph held the answer — fall back to
@@ -1132,6 +1140,7 @@ export function buildServerWithRootControl(initialRoot, options = {}) {
1132
1140
  supplements: [
1133
1141
  ...(dnaSupplement ? [dnaSupplement] : []),
1134
1142
  ...stateGrounding,
1143
+ ...recentTasks,
1135
1144
  ...hits
1136
1145
  // State hits are delivered through the State section above, not as raw search lines.
1137
1146
  .filter((hit) => !["constraints", "decisions", "bugs", "findings"].includes(hit.kind) && !isStateKind(hit.kind))
@@ -17,7 +17,7 @@ export declare function boundedTaskReport(report: ReturnType<typeof readTaskRepo
17
17
  finished_at: string | null;
18
18
  state: "open" | "completed" | "interrupted";
19
19
  };
20
- coverage: "delivered" | "no-delivery-observed" | "no-relevant-memory";
20
+ coverage: "no-delivery-observed" | "no-relevant-memory" | "delivered";
21
21
  content_hash: string;
22
22
  unknowns: string[];
23
23
  deliveries: {
@@ -73,7 +73,7 @@ export declare function boundedTaskReport(report: ReturnType<typeof readTaskRepo
73
73
  title: string;
74
74
  home: "public" | "private";
75
75
  operation: "updated" | "created";
76
- durability: "committed" | "pushed" | "local";
76
+ durability: "local" | "committed" | "pushed";
77
77
  }[];
78
78
  refusals: ({
79
79
  source: "native-edit-gate";
@@ -106,7 +106,7 @@ export declare function boundedTaskReportForHost(report: ReturnType<typeof readT
106
106
  finished_at: string | null;
107
107
  state: "open" | "completed" | "interrupted";
108
108
  };
109
- coverage: "delivered" | "no-delivery-observed" | "no-relevant-memory";
109
+ coverage: "no-delivery-observed" | "no-relevant-memory" | "delivered";
110
110
  content_hash: string;
111
111
  unknowns: string[];
112
112
  deliveries: {
@@ -162,7 +162,7 @@ export declare function boundedTaskReportForHost(report: ReturnType<typeof readT
162
162
  title: string;
163
163
  home: "public" | "private";
164
164
  operation: "updated" | "created";
165
- durability: "committed" | "pushed" | "local";
165
+ durability: "local" | "committed" | "pushed";
166
166
  }[];
167
167
  refusals: ({
168
168
  source: "native-edit-gate";
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { TaskIdSchema, ReportClaimSchema, LessonReferenceSchema, finishReportTask, listReportTasks, readTaskReport, readLessonHistory, recordReportClaim, reportPresentationEnabled, startReportTask } from "../core/taskReport.js";
4
+ import { persistTaskRecord } from "../core/taskRecord.js";
4
5
  import { reportSourceSnapshot, runReportConformance } from "../core/taskReportEvidence.js";
5
6
  import { renderTaskReport, writeTaskReportHtml } from "../core/taskReportRender.js";
6
7
  function applicationReferences(report) {
@@ -73,7 +74,18 @@ export function registerTaskReportTools(server, getRoot, getStore) {
73
74
  if (action === "start") {
74
75
  if (!title || applications?.length || outcome)
75
76
  throw new Error("start requires a short task title and no completion evidence");
76
- const task = startReportTask(root, title, task_id);
77
+ let task;
78
+ try {
79
+ task = startReportTask(root, title, task_id);
80
+ }
81
+ catch (error) {
82
+ // A native prompt task already exists under this exact ID (opened by the
83
+ // host hook). Its persisted title is authoritative; a paraphrased title
84
+ // from the model must not fork a second report or fail the start.
85
+ if (!task_id || !/different title/.test(error.message))
86
+ throw error;
87
+ task = readTaskReport(root, task_id, reportSourceSnapshot(root).hash).task;
88
+ }
77
89
  const launcher = verificationLauncher();
78
90
  return { content: [{ type: "text", text: `Task ${task.task_id} · ${task.state}. Pass task_id to every hunch_context and decision/correction/finding capture call. Before the final response, finish with hunch_task and include its contribution card. For checks use this exact installation (the global hunch binary may be stale): ${launcher.shell} task verify ${task.task_id} -- <command> [arguments]. The default budget is 2 minutes; add --timeout <seconds> before -- for a long suite.` }], structuredContent: { task, verification_argv: [...launcher.argv, "task", "verify", task.task_id, "--"] } };
79
91
  }
@@ -90,15 +102,29 @@ export function registerTaskReportTools(server, getRoot, getStore) {
90
102
  catch { /* unknowns disclose it */ }
91
103
  }
92
104
  finishReportTask(root, task_id, outcome ?? "completed");
93
- const report = readTaskReport(root, task_id, reportSourceSnapshot(root).hash);
94
- const show = reportPresentationEnabled(root);
95
- let file = null;
105
+ // The finished task becomes graph memory through the normal capture path;
106
+ // a failed write is disclosed on the card, never a reason to lose it.
107
+ let graph = null;
108
+ let graphNote = "";
96
109
  try {
97
- file = writeTaskReportHtml(root, task_id);
110
+ const saved = persistTaskRecord(root, getStore(), task_id);
111
+ if (saved) {
112
+ graph = { id: saved.record.id, home: saved.home, flushed: saved.flushed, changed: saved.changed };
113
+ graphNote = `\nGraph ${saved.changed ? "saved" : "already saved"} as ${saved.record.id} (${saved.home}${saved.flushed ? `, ${saved.flushed}` : ""})`;
114
+ }
115
+ else {
116
+ graphNote = "\nGraph nothing to keep (no observation, or task records disabled)";
117
+ }
118
+ }
119
+ catch (error) {
120
+ graphNote = `\nGraph not saved: ${error.message}`;
98
121
  }
99
- catch { /* retained report remains inspectable through MCP */ }
100
- const card = file ? renderTaskReport(report).replace(/^Evidence .*$/m, `Evidence [Open local report](<${file}>)`) : renderTaskReport(report);
101
- return { content: [{ type: "text", text: show ? card : "Task report retained. Automatic presentation is disabled; omit the contribution card from the final response." }], structuredContent: { ...boundedTaskReportForHost(report), presentation_enabled: show, contribution_card: show ? card : null, report_path: file } };
122
+ const report = readTaskReport(root, task_id, reportSourceSnapshot(root).hash);
123
+ const show = reportPresentationEnabled(root);
124
+ // The HTML evidence view is rendered on demand (hunch_report(html: true),
125
+ // `hunch report <id> --html`, or the VS Code view); finish writes no file.
126
+ const card = renderTaskReport(report) + graphNote;
127
+ return { content: [{ type: "text", text: show ? card : "Task report retained. Automatic presentation is disabled; omit the contribution card from the final response." }], structuredContent: { ...boundedTaskReportForHost(report), presentation_enabled: show, contribution_card: show ? card : null, report_path: null, graph_record: graph } };
102
128
  }
103
129
  catch (error) {
104
130
  const message = `Task report unavailable: ${error.message}`;
@@ -1,5 +1,5 @@
1
1
  import { type HunchPaths } from "../core/paths.js";
2
- import { type Component, type Constraint, type Bug, type Decision, type Symbol, type Edge, type Finding, type EntityKind, type EntityFor } from "../core/types.js";
2
+ import { type Component, type Constraint, type Bug, type Decision, type Symbol, type Edge, type Finding, type EntityKind, type EntityFor, type TaskRecord } from "../core/types.js";
3
3
  import { type DB } from "./db.js";
4
4
  import { type Embedder } from "./embedder.js";
5
5
  import { JsonStore } from "./jsonStore.js";
@@ -405,6 +405,10 @@ export declare class HunchStore {
405
405
  * glob, and the queried scope may be either too. Advisory only — findings never
406
406
  * enter any block path. Sorted worst-first, then id for stable output. */
407
407
  liveFindingsFor(scope: string): Finding[];
408
+ /** Finished agent tasks that touched a file or glob (rule-checked changes and
409
+ * denied edits), newest first. Graph memory, so it spans machines and survives
410
+ * the local ledger's retention window. */
411
+ tasksFor(scope: string, limit?: number): TaskRecord[];
408
412
  /** The causal chain behind a constraint — the WHY a diff-only reviewer can't see.
409
413
  * Deterministic graph join: constraint → source_decision (the decision that
410
414
  * motivated the guard) → the bug whose root cause spawned it (via
@@ -491,6 +491,14 @@ export class HunchStore {
491
491
  fts(f.id, "findings", f.title, `${f.observation} ${f.evidence.join(" ")} ${f.affected_files.join(" ")} ${f.affected_symbols.join(" ")} ${f.triage}`);
492
492
  }
493
493
  counts.findings = fnds.length;
494
+ // Tasks (finished agent work as graph memory): same FTS-only ride. Title +
495
+ // the lesson/save/application record ids and touched files, so "what did
496
+ // an agent do around X" and a record id both hit.
497
+ const tasks = this.recs("tasks");
498
+ for (const t of tasks) {
499
+ fts(t.id, "tasks", t.title, `${t.lessons.map((l) => `${l.record_id} ${l.title}`).join(" ")} ${t.applied.map((a) => a.record_id).join(" ")} ${t.saved.map((s) => s.record_id).join(" ")} ${t.files.join(" ")} ${t.state} ${t.coverage}`);
500
+ }
501
+ counts.tasks = tasks.length;
494
502
  // nuryel.state/1 kinds (receipts, commitments, derived, entities, relationships):
495
503
  // advisory records on the same FTS-only ride as runbooks/findings — no dedicated
496
504
  // SQL table. kind = the store kind; title = the subject key; body = the human words
@@ -1435,6 +1443,16 @@ export class HunchStore {
1435
1443
  || f.affected_symbols.some((s) => s === scope))
1436
1444
  .sort((a, b) => (SEV_FINDING[b.severity] ?? 0) - (SEV_FINDING[a.severity] ?? 0) || a.id.localeCompare(b.id));
1437
1445
  }
1446
+ /** Finished agent tasks that touched a file or glob (rule-checked changes and
1447
+ * denied edits), newest first. Graph memory, so it spans machines and survives
1448
+ * the local ledger's retention window. */
1449
+ tasksFor(scope, limit = 8) {
1450
+ const t = toPosixTarget(scope);
1451
+ return this.recs("tasks")
1452
+ .filter((r) => r.files.some((f) => pathMatchesGlob(t, f) || pathMatchesGlob(f, t) || pathsRelated(toPosixTarget(f), t)))
1453
+ .sort((a, b) => b.finished_at.localeCompare(a.finished_at) || a.id.localeCompare(b.id))
1454
+ .slice(0, Math.max(1, limit));
1455
+ }
1438
1456
  /** The causal chain behind a constraint — the WHY a diff-only reviewer can't see.
1439
1457
  * Deterministic graph join: constraint → source_decision (the decision that
1440
1458
  * motivated the guard) → the bug whose root cause spawned it (via
@@ -25,7 +25,7 @@ export declare function createTaskReporter(root: string): {
25
25
  /** The caller supplies the exact envelope it issued plus snapshots of the
26
26
  * included revisions. Return the occurrence with the context to the agent.
27
27
  * Issuance alone does not prove the model applied or even attended to it. */
28
- delivered(taskId: string, envelope: DeliveryEnvelope, records: ReportRecord[], occurrenceId?: string): string;
28
+ delivered(taskId: string, envelope: DeliveryEnvelope, records: ReportRecord[], occurrenceId?: string, target?: string): string;
29
29
  applied(taskId: string, claim: ReportClaim): string;
30
30
  /** Runs locally as argv, without a shell. Only use commands authorized by
31
31
  * the task owner. This API does not accept remote claimed-success receipts. */
@@ -1,6 +1,5 @@
1
1
  /** Provider-neutral, local engine integration. The authorized harness owns
2
2
  * lifecycle and display; neither operation depends on model compliance. */
3
- import { realpathSync } from "node:fs";
4
3
  import { z } from "zod";
5
4
  import { finishReportTask, listReportTasks, readTaskReport, readLessonHistory, recordReportClaim, recordTaskDelivery, reportHash, reportPresentationEnabled, startReportTask } from "./core/taskReport.js";
6
5
  import { DEFAULT_CHECK_TIMEOUT_MS, reportSourceSnapshot, runReportCheck, runReportConformance } from "./core/taskReportEvidence.js";
@@ -10,12 +9,14 @@ import { hunchPaths } from "./core/paths.js";
10
9
  import { HunchStore } from "./store/hunchStore.js";
11
10
  export { TASK_REPORT_SCHEMA, TaskIdSchema } from "./core/taskReport.js";
12
11
  export { renderTaskReport, renderTaskReportHtml } from "./core/taskReportRender.js";
12
+ import { canonicalReportRoot } from "./core/taskReportPaths.js";
13
+ import { persistTaskRecord } from "./core/taskRecord.js";
13
14
  const IdentitySchema = z.object({ task: z.string().min(1).max(1024), attempt: z.string().min(1).max(1024) }).strict();
14
15
  /** Create this only after authorizing a local repository/worktree. A task ID is
15
16
  * a correlation reference, never an access token. Remote adapters must enforce
16
17
  * their own principal/partition boundary before reaching this local API. */
17
18
  export function createTaskReporter(root) {
18
- const scope = realpathSync(root);
19
+ const scope = canonicalReportRoot(root);
19
20
  const report = (taskId) => readTaskReport(scope, taskId, reportSourceSnapshot(scope).hash);
20
21
  return {
21
22
  /** Omit identity for a fresh task, or supply the harness's stable task AND
@@ -28,8 +29,8 @@ export function createTaskReporter(root) {
28
29
  /** The caller supplies the exact envelope it issued plus snapshots of the
29
30
  * included revisions. Return the occurrence with the context to the agent.
30
31
  * Issuance alone does not prove the model applied or even attended to it. */
31
- delivered(taskId, envelope, records, occurrenceId) {
32
- return recordTaskDelivery(scope, taskId, envelope, records, occurrenceId);
32
+ delivered(taskId, envelope, records, occurrenceId, target) {
33
+ return recordTaskDelivery(scope, taskId, envelope, records, occurrenceId, target);
33
34
  },
34
35
  applied(taskId, claim) { return recordReportClaim(scope, taskId, claim); },
35
36
  /** Runs locally as argv, without a shell. Only use commands authorized by
@@ -57,6 +58,17 @@ export function createTaskReporter(root) {
57
58
  catch { /* the report's unknowns disclose it */ }
58
59
  }
59
60
  finishReportTask(scope, taskId, outcome);
61
+ // Graph memory of the finished task; disclosed in the report, never blocking.
62
+ try {
63
+ const store = new HunchStore(hunchPaths(scope));
64
+ try {
65
+ persistTaskRecord(scope, store, taskId);
66
+ }
67
+ finally {
68
+ store.close();
69
+ }
70
+ }
71
+ catch { /* the ledger keeps the observations; the graph write is retried on the next finish */ }
60
72
  const result = report(taskId);
61
73
  return { report: result, contribution_card: reportPresentationEnabled(scope) ? renderTaskReport(result) : null };
62
74
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@davesheffer/hunch",
3
- "version": "1.33.0",
3
+ "version": "1.36.0",
4
4
  "mcpName": "io.github.davesheffer/hunch",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Dave Sheffer <dave.sheffer1@gmail.com>",
package/server.json CHANGED
@@ -7,13 +7,13 @@
7
7
  "source": "github"
8
8
  },
9
9
  "websiteUrl": "https://www.hunchmemory.com",
10
- "version": "1.33.0",
10
+ "version": "1.36.0",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "registryBaseUrl": "https://registry.npmjs.org",
15
15
  "identifier": "@davesheffer/hunch",
16
- "version": "1.33.0",
16
+ "version": "1.36.0",
17
17
  "runtimeHint": "npx",
18
18
  "packageArguments": [
19
19
  {