@qvac/harness 0.2.7 → 0.2.9

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 (184) hide show
  1. package/dist/harness.bundle +70 -16
  2. package/dist/prebuilds-manifest.json +8 -0
  3. package/dist-lib/index.d.ts +2 -1
  4. package/dist-lib/index.js +60 -59
  5. package/dist-lib/lib/audio-transcode-bare.js +2 -2
  6. package/dist-lib/lib/capabilities/completion.d.ts +35 -2
  7. package/dist-lib/lib/capabilities/completion.js +114 -48
  8. package/dist-lib/lib/capabilities/download.js +2 -2
  9. package/dist-lib/lib/capabilities/speech-text.js +1 -1
  10. package/dist-lib/lib/capabilities/tool-prompt-log.js +1 -1
  11. package/dist-lib/lib/capabilities/tool-selection.js +2 -2
  12. package/dist-lib/lib/capabilities/tool-turns.js +1 -1
  13. package/dist-lib/lib/capabilities/usage-breakdown.js +1 -1
  14. package/dist-lib/lib/capabilities/voice.js +3 -3
  15. package/dist-lib/lib/connect.js +12 -11
  16. package/dist-lib/lib/context-window.js +1 -1
  17. package/dist-lib/lib/contract-types.d.ts +1 -0
  18. package/dist-lib/lib/docx/index.js +3 -3
  19. package/dist-lib/lib/hardware/capability-probe.js +3 -3
  20. package/dist-lib/lib/hardware/gpu-probe-addon.js +2 -2
  21. package/dist-lib/lib/hardware/gpu-probe-entry.js +1 -1
  22. package/dist-lib/lib/helpers/markup-stream-filter.js +1 -1
  23. package/dist-lib/lib/helpers/run-outcome.js +1 -1
  24. package/dist-lib/lib/helpers/spawn-path.d.ts +1 -1
  25. package/dist-lib/lib/helpers/thinking.js +2 -2
  26. package/dist-lib/lib/helpers/tool-intent.js +1 -1
  27. package/dist-lib/lib/helpers/tool-label.js +3 -3
  28. package/dist-lib/lib/hooks/built-in/arg-repair.d.ts +1 -1
  29. package/dist-lib/lib/hooks/built-in/arg-repair.js +1 -1
  30. package/dist-lib/lib/hooks/built-in/egress.d.ts +1 -1
  31. package/dist-lib/lib/hooks/built-in/egress.js +2 -2
  32. package/dist-lib/lib/hooks/built-in/index.js +3 -3
  33. package/dist-lib/lib/hooks/built-in/skill-catalog.d.ts +1 -1
  34. package/dist-lib/lib/hooks/pipeline.js +4 -4
  35. package/dist-lib/lib/hooks/registry.js +1 -1
  36. package/dist-lib/lib/hooks/run.js +1 -1
  37. package/dist-lib/lib/models/model-catalog.js +4 -4
  38. package/dist-lib/lib/models/model-delete.js +1 -1
  39. package/dist-lib/lib/models/model-handle.js +1 -1
  40. package/dist-lib/lib/models/model-list.js +1 -1
  41. package/dist-lib/lib/models/model-pool.js +8 -8
  42. package/dist-lib/lib/models/model-source.js +1 -1
  43. package/dist-lib/lib/models/music-catalog.d.ts +1 -1
  44. package/dist-lib/lib/no-redirect-fetch-bare.js +3 -3
  45. package/dist-lib/lib/no-redirect-fetch-impl.js +1 -1
  46. package/dist-lib/lib/no-redirect-fetch-node.js +2 -2
  47. package/dist-lib/lib/resolution-detector.js +1 -1
  48. package/dist-lib/lib/sdk-loader.js +2 -2
  49. package/dist-lib/lib/sdk-storage.js +1 -1
  50. package/dist-lib/lib/serve.js +11 -10
  51. package/dist-lib/lib/spawn.js +3 -3
  52. package/dist-lib/lib/staging.js +1 -1
  53. package/dist-lib/lib/tools/catalog.js +1 -1
  54. package/dist-lib/lib/tools/create-documents.js +2 -2
  55. package/dist-lib/lib/tools/edit-documents.js +2 -2
  56. package/dist-lib/lib/tools/edit-image.js +2 -2
  57. package/dist-lib/lib/tools/exec/adapters/python/attachments.js +2 -2
  58. package/dist-lib/lib/tools/exec/adapters/python/create-effect.js +1 -1
  59. package/dist-lib/lib/tools/exec/adapters/python/loader.js +1 -1
  60. package/dist-lib/lib/tools/exec/adapters/python/memfs.js +2 -2
  61. package/dist-lib/lib/tools/exec/adapters/python/pyodide.js +6 -6
  62. package/dist-lib/lib/tools/exec/adapters/python/python-adapter.js +3 -3
  63. package/dist-lib/lib/tools/exec/adapters/python/run-session.js +5 -5
  64. package/dist-lib/lib/tools/exec/adapters/python/wheels.js +1 -1
  65. package/dist-lib/lib/tools/exec/adapters/python/worker/client.js +3 -3
  66. package/dist-lib/lib/tools/exec/adapters/python/worker/entry.js +4 -4
  67. package/dist-lib/lib/tools/exec/adapters/shell/shell-adapter.js +1 -1
  68. package/dist-lib/lib/tools/exec/obsidian/cli-process.js +2 -2
  69. package/dist-lib/lib/tools/exec/obsidian/cli.js +4 -4
  70. package/dist-lib/lib/tools/exec/obsidian/command.js +1 -1
  71. package/dist-lib/lib/tools/exec/obsidian/route.js +7 -7
  72. package/dist-lib/lib/tools/exec/obsidian/vault-create.js +2 -2
  73. package/dist-lib/lib/tools/exec/obsidian/vault-fs.js +6 -6
  74. package/dist-lib/lib/tools/exec/obsidian/vault-paths.js +2 -2
  75. package/dist-lib/lib/tools/exec/obsidian/vault-read.js +1 -1
  76. package/dist-lib/lib/tools/exec/obsidian/vault-write.js +2 -2
  77. package/dist-lib/lib/tools/exec/runner.js +1 -1
  78. package/dist-lib/lib/tools/exec.js +13 -13
  79. package/dist-lib/lib/tools/file-glob.js +3 -3
  80. package/dist-lib/lib/tools/fs/local.js +1 -1
  81. package/dist-lib/lib/tools/fs/remote.js +1 -1
  82. package/dist-lib/lib/tools/fs/walk.js +2 -2
  83. package/dist-lib/lib/tools/generate-image.js +4 -4
  84. package/dist-lib/lib/tools/generate-music.js +6 -6
  85. package/dist-lib/lib/tools/grep.js +6 -6
  86. package/dist-lib/lib/tools/http-request/truncate-response.js +1 -1
  87. package/dist-lib/lib/tools/http-request.js +9 -9
  88. package/dist-lib/lib/tools/mcp/utils.js +1 -1
  89. package/dist-lib/lib/tools/mcp-call.js +8 -8
  90. package/dist-lib/lib/tools/operations/builders.d.ts +1 -1
  91. package/dist-lib/lib/tools/operations/builders.js +1 -1
  92. package/dist-lib/lib/tools/operations/compile.js +1 -1
  93. package/dist-lib/lib/tools/operations/manifest.d.ts +16 -16
  94. package/dist-lib/lib/tools/operations/manifest.js +1 -1
  95. package/dist-lib/lib/tools/outbound-guard.js +1 -1
  96. package/dist-lib/lib/tools/rag-search.js +1 -1
  97. package/dist-lib/lib/tools/read-files.js +3 -3
  98. package/dist-lib/lib/tools/skill.js +8 -8
  99. package/dist-lib/lib/tools/skills/auth-resolver.js +2 -2
  100. package/dist-lib/lib/tools/skills/bin-check.js +1 -1
  101. package/dist-lib/lib/tools/skills/bundled-dir.js +2 -2
  102. package/dist-lib/lib/tools/skills/catalog.js +10 -10
  103. package/dist-lib/lib/tools/skills/cli-schema-check.js +1 -1
  104. package/dist-lib/lib/tools/skills/cli-schema-load.js +1 -1
  105. package/dist-lib/lib/tools/skills/cli-schema.js +4 -4
  106. package/dist-lib/lib/tools/skills/credential-check.js +3 -3
  107. package/dist-lib/lib/tools/skills/credential-grants.js +1 -1
  108. package/dist-lib/lib/tools/skills/credential-health.js +2 -2
  109. package/dist-lib/lib/tools/skills/frontmatter-parser.js +1 -1
  110. package/dist-lib/lib/tools/skills/index.js +5 -5
  111. package/dist-lib/lib/tools/skills/mention.js +1 -1
  112. package/dist-lib/lib/tools/skills/overlay-crud.js +1 -1
  113. package/dist-lib/lib/tools/skills/setup-routes.js +1 -1
  114. package/dist-lib/lib/tools/skills/skill-settings.js +1 -1
  115. package/dist-lib/lib/tools/skills/skill-state-constants.d.ts +8 -8
  116. package/dist-lib/lib/tools/skills/skill-state.js +9 -9
  117. package/dist-lib/lib/tools/toolsets.d.ts +1 -1
  118. package/dist-lib/lib/tools/url-guard.js +2 -2
  119. package/dist-lib/lib/tools/weather-lookup/place.d.ts +11 -0
  120. package/dist-lib/lib/tools/weather-lookup/place.js +152 -0
  121. package/dist-lib/lib/tools/weather-lookup/report.d.ts +37 -0
  122. package/dist-lib/lib/tools/weather-lookup/report.js +56 -0
  123. package/dist-lib/lib/tools/weather-lookup.d.ts +8 -0
  124. package/dist-lib/lib/tools/weather-lookup.js +110 -0
  125. package/dist-lib/lib/tools/web-fetch.js +10 -10
  126. package/dist-lib/lib/tools/web-search.js +2 -2
  127. package/dist-lib/lib/transport.js +1 -1
  128. package/dist-lib/lib/validating-lookup.js +1 -1
  129. package/dist-lib/lib/web-fetch/embedded-state.js +1 -1
  130. package/dist-lib/lib/web-fetch/extract.js +1 -1
  131. package/dist-lib/lib/web-fetch/images.js +1 -1
  132. package/dist-lib/lib/web-fetch/video.js +1 -1
  133. package/dist-lib/lib/web-search/engine-registry.js +7 -7
  134. package/dist-lib/lib/web-search/engines/aol.js +3 -3
  135. package/dist-lib/lib/web-search/engines/bing.js +4 -4
  136. package/dist-lib/lib/web-search/engines/brave.js +2 -2
  137. package/dist-lib/lib/web-search/engines/duckduckgo.js +3 -3
  138. package/dist-lib/lib/web-search/engines/google.js +4 -4
  139. package/dist-lib/lib/web-search/engines/wikipedia.js +2 -2
  140. package/dist-lib/lib/web-search/engines/yahoo.js +3 -3
  141. package/dist-lib/lib/web-search/fetch-html.js +1 -1
  142. package/dist-lib/lib/web-search/merge-results.js +1 -1
  143. package/dist-lib/lib/web-search/orchestrator.js +3 -3
  144. package/dist-lib/lib/wire.js +28 -0
  145. package/dist-lib/schema/baseline.js +1 -1
  146. package/dist-lib/schema/build.js +3 -3
  147. package/dist-lib/schema/harness.js +5 -2
  148. package/dist-lib/schema/release-tags.d.ts +2 -1
  149. package/dist-lib/schema/release-tags.js +9 -7
  150. package/dist-lib/spec/hrpc/messages.js +22 -7
  151. package/dist-lib/spec/hyperschema/index.js +22 -7
  152. package/dist-lib/spec/hyperschema/schema.json +14 -1
  153. package/dist-lib/spec/hyperschema/types.d.ts +3 -2
  154. package/package.json +21 -8
  155. package/worker/harness-sidecar.mjs +2 -0
  156. package/.claude/skills/asana/SKILL.md +0 -86
  157. package/.claude/skills/gh-stack/SKILL.md +0 -181
  158. package/.claude/skills/gh-stack/references/commands.md +0 -177
  159. package/.claude/skills/gh-stack/references/stack-design.md +0 -97
  160. package/.claude/skills/gh-stack/references/troubleshooting.md +0 -159
  161. package/.claude/skills/js-house-style/SKILL.md +0 -671
  162. package/.claude/skills/kvcache/SKILL.md +0 -171
  163. package/.claude/skills/pr-create/SKILL.md +0 -180
  164. package/.claude/skills/pr-review/SKILL.md +0 -217
  165. package/CLAUDE.md +0 -39
  166. package/docs/decisions/2026-05-29-kvcache-tool-turns.md +0 -75
  167. package/docs/decisions/2026-06-02-kvcache-tool-turns-reenabled.md +0 -127
  168. package/docs/decisions/2026-06-23-android-cpu-llm-defaults.md +0 -126
  169. package/docs/decisions/2026-07-29-assistant-owned-storage-layout.md +0 -88
  170. package/docs/decisions/2026-08-04-sidecar-orphan-reaping.md +0 -79
  171. package/docs/decisions/2026-08-11-pyodide-worker-thread.md +0 -68
  172. package/docs/decisions/2026-08-17-harness-hook-pipeline.md +0 -84
  173. package/docs/decisions/2026-08-17-harness-outbound-egress-guard.md +0 -176
  174. package/docs/decisions/2026-08-20-chat-prompt-prefix-is-stable.md +0 -95
  175. package/docs/decisions/2026-08-20-kvcache-static-placement.md +0 -109
  176. package/docs/decisions/2026-08-21-vendored-python-wheels.md +0 -85
  177. package/docs/decisions/2026-08-26-exec-is-not-gated-by-skills.md +0 -64
  178. package/docs/decisions/2026-08-27-writable-skills-overlay.md +0 -56
  179. package/docs/decisions/2026-09-01-skill-operation-manifests.md +0 -53
  180. package/docs/decisions/2026-09-01-usage-breakdown-is-measured.md +0 -78
  181. package/docs/decisions/2026-09-03-usage-breakdown-reported-by-the-harness.md +0 -136
  182. package/docs/decisions/INDEX.md +0 -38
  183. package/docs/decisions/TEMPLATE.md +0 -32
  184. package/docs/kvcache-reference.md +0 -655
@@ -1,4 +1,4 @@
1
- import { normalizeUrl } from "./url-normalize.js";
1
+ import { normalizeUrl } from './url-normalize.js';
2
2
  const WEAK_RESULT_PENALTY = 0.2;
3
3
  function scoreFor(r) {
4
4
  const base = 1 / r.position;
@@ -1,6 +1,6 @@
1
- import { DEFAULT_MAX_RESULTS, ENGINES } from "./engine-registry.js";
2
- import { TimeoutError } from "./fetch-html.js";
3
- import { mergeResults } from "./merge-results.js";
1
+ import { DEFAULT_MAX_RESULTS, ENGINES } from './engine-registry.js';
2
+ import { TimeoutError } from './fetch-html.js';
3
+ import { mergeResults } from './merge-results.js';
4
4
  export function classifyEngineError(reason) {
5
5
  return reason instanceof TimeoutError ? 'timeout' : 'error';
6
6
  }
@@ -32,6 +32,20 @@ export function toWire(event) {
32
32
  const { type, ...metrics } = event;
33
33
  return { type, metrics };
34
34
  }
35
+ case 'inference-call':
36
+ return { type: 'inference-call', payload: event.call };
37
+ case 'inference-sent':
38
+ return {
39
+ type: 'inference-sent',
40
+ payload: {
41
+ round: event.round,
42
+ droppedTurns: event.droppedTurns,
43
+ messages: event.messages,
44
+ tokens: event.tokens,
45
+ outcome: event.outcome,
46
+ reason: event.reason
47
+ }
48
+ };
35
49
  case 'error':
36
50
  return { type: 'error', message: event.message };
37
51
  case 'aborted':
@@ -73,6 +87,20 @@ export function fromWire(event) {
73
87
  };
74
88
  case 'metrics':
75
89
  return { type: 'metrics', ...event.metrics };
90
+ case 'inference-call':
91
+ return { type: 'inference-call', call: event.payload };
92
+ case 'inference-sent': {
93
+ const sent = (event.payload ?? {});
94
+ return {
95
+ type: 'inference-sent',
96
+ messages: sent.messages,
97
+ round: Number(sent.round ?? 0),
98
+ droppedTurns: Number(sent.droppedTurns ?? 0),
99
+ tokens: sent.tokens,
100
+ outcome: sent.outcome || 'completed',
101
+ reason: sent.reason || undefined
102
+ };
103
+ }
76
104
  case 'error':
77
105
  return { type: 'error', message: event.message ?? 'harness error' };
78
106
  case 'aborted':
@@ -2,7 +2,7 @@ import fs from 'bare-fs';
2
2
  import path from 'bare-path';
3
3
  import process from 'bare-process';
4
4
  import { spawnSync } from 'bare-subprocess';
5
- import { previousReleaseTags } from "./release-tags.js";
5
+ import { previousReleaseTags } from './release-tags.js';
6
6
  export function rewindSpec(root, dirs, { carries, keep }) {
7
7
  if (process.env.SCHEMA_NO_BASELINE)
8
8
  return [];
@@ -3,9 +3,9 @@ import { fileURLToPath } from 'bare-url';
3
3
  import HRPCBuilder from 'hrpc';
4
4
  import Hyperschema from 'hyperschema';
5
5
  import HyperschemaTS from 'hyperschema-ts';
6
- import { resetHrpcIds, rewindSpec, unstageSpec } from "./baseline.js";
7
- import { writeBind, writeClient } from "./generate.js";
8
- import { registerHarnessApi, registerHarnessTypes } from "./harness.js";
6
+ import { resetHrpcIds, rewindSpec, unstageSpec } from './baseline.js';
7
+ import { writeBind, writeClient } from './generate.js';
8
+ import { registerHarnessApi, registerHarnessTypes } from './harness.js';
9
9
  const dir = path.dirname(fileURLToPath(import.meta.url));
10
10
  const ROOT = path.join(dir, '..');
11
11
  const SPEC_DIR = path.join(dir, '..', 'spec');
@@ -107,7 +107,8 @@ export function registerHarnessTypes(ns) {
107
107
  { name: 'grantedDirs', type: 'string', array: true },
108
108
  { name: 'grantedDrives', type: '@harness/granted-drive', array: true },
109
109
  { name: 'payload', type: 'json' },
110
- { name: 'grantedWriteDirs', type: 'string', array: true }
110
+ { name: 'grantedWriteDirs', type: 'string', array: true },
111
+ { name: 'captureInferenceCalls', type: 'bool' }
111
112
  ]
112
113
  });
113
114
  ns.register({
@@ -128,7 +129,9 @@ export function registerHarnessTypes(ns) {
128
129
  'question-ask',
129
130
  'done',
130
131
  'tool-activity',
131
- 'drive-ask'
132
+ 'drive-ask',
133
+ 'inference-call',
134
+ 'inference-sent'
132
135
  ],
133
136
  strings: true
134
137
  });
@@ -1,4 +1,5 @@
1
- export declare function currentReleaseLine(root: string): string;
1
+ import { Version } from 'bare-semver';
2
+ export declare function currentReleaseVersion(root: string): Version;
2
3
  export declare function previousReleaseTags(root: string, { count, carries }: {
3
4
  count?: number;
4
5
  carries: string;
@@ -2,24 +2,26 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { spawnSync } from 'child_process';
4
4
  import { Version } from 'bare-semver';
5
- export function currentReleaseLine(root) {
5
+ export function currentReleaseVersion(root) {
6
6
  const file = path.join(root, 'package.json');
7
7
  const { version } = JSON.parse(fs.readFileSync(file, 'utf8'));
8
- const parsed = /^(\d+)\.(\d+)/.exec(version);
9
- if (!parsed)
10
- throw new Error(`no release line in package version ${version}`);
11
- return `${parsed[1]}.${parsed[2]}`;
8
+ try {
9
+ return Version.parse(version);
10
+ }
11
+ catch {
12
+ throw new Error(`no release version in package version ${version}`);
13
+ }
12
14
  }
13
15
  const TAG_PREFIX = 'v';
14
16
  export function previousReleaseTags(root, { count = 3, carries }) {
15
- const current = currentReleaseLine(root);
17
+ const current = currentReleaseVersion(root);
16
18
  const listed = spawnSync('git', ['tag', '-l', `${TAG_PREFIX}*`], { cwd: root });
17
19
  if (listed.status !== 0)
18
20
  throw new Error(`git tag -l failed: ${listed.stderr ?? ''}`);
19
21
  const newestPerLine = new Map();
20
22
  for (const line of (listed.stdout?.toString() ?? '').split('\n')) {
21
23
  const parsed = parseTag(line.trim());
22
- if (!parsed || parsed.line === current)
24
+ if (!parsed || Version.compare(parsed.version, current) > 0)
23
25
  continue;
24
26
  const winner = newestPerLine.get(parsed.line);
25
27
  if (!winner || Version.compare(parsed.version, winner.version) > 0) {
@@ -1,12 +1,12 @@
1
1
  // This file is autogenerated by the hyperschema compiler
2
- // Schema Version: 8
2
+ // Schema Version: 9
3
3
  /* eslint-disable camelcase */
4
4
  /* eslint-disable quotes */
5
5
  /* eslint-disable space-before-function-paren */
6
6
 
7
7
  import { c } from 'hyperschema/runtime'
8
8
 
9
- const VERSION = 8
9
+ const VERSION = 9
10
10
 
11
11
  // eslint-disable-next-line no-unused-vars
12
12
  let version = VERSION
@@ -478,7 +478,8 @@ const encoding11 = {
478
478
  ((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
479
479
  ((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
480
480
  ((version >= 5 && m.payload) ? 8388608 : 0) |
481
- ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
481
+ ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
482
+ ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
482
483
 
483
484
  encoding10.preencode(state, m.type)
484
485
  c.uint.preencode(state, flags)
@@ -533,7 +534,8 @@ const encoding11 = {
533
534
  ((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
534
535
  ((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
535
536
  ((version >= 5 && m.payload) ? 8388608 : 0) |
536
- ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
537
+ ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
538
+ ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
537
539
 
538
540
  encoding10.encode(state, m.type)
539
541
  c.uint.encode(state, flags)
@@ -592,7 +594,8 @@ const encoding11 = {
592
594
  grantedDirs: (version >= 5 && (flags & 2097152) !== 0) ? encoding11_22.decode(state) : null,
593
595
  grantedDrives: (version >= 5 && (flags & 4194304) !== 0) ? encoding11_23.decode(state) : null,
594
596
  payload: (version >= 5 && (flags & 8388608) !== 0) ? c.json.decode(state) : null,
595
- grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null
597
+ grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
598
+ captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0)
596
599
  }
597
600
  }
598
601
  }
@@ -613,13 +616,15 @@ const encoding12_enum = {
613
616
  "question-ask": 'question-ask',
614
617
  done: 'done',
615
618
  "tool-activity": 'tool-activity',
616
- "drive-ask": 'drive-ask'
619
+ "drive-ask": 'drive-ask',
620
+ "inference-call": 'inference-call',
621
+ "inference-sent": 'inference-sent'
617
622
  }
618
623
 
619
624
  // @harness/completion-event-type enum
620
625
  const encoding12 = {
621
626
  preencode (state, m) {
622
- state.end++ // max enum is 16 so always one byte
627
+ state.end++ // max enum is 18 so always one byte
623
628
  },
624
629
  encode (state, m) {
625
630
  switch (m) {
@@ -671,6 +676,12 @@ const encoding12 = {
671
676
  case 'drive-ask':
672
677
  c.uint.encode(state, 16)
673
678
  break
679
+ case 'inference-call':
680
+ c.uint.encode(state, 17)
681
+ break
682
+ case 'inference-sent':
683
+ c.uint.encode(state, 18)
684
+ break
674
685
  default:
675
686
  throw new Error('Unknown enum')
676
687
  }
@@ -709,6 +720,10 @@ const encoding12 = {
709
720
  return 'tool-activity'
710
721
  case 16:
711
722
  return 'drive-ask'
723
+ case 17:
724
+ return 'inference-call'
725
+ case 18:
726
+ return 'inference-sent'
712
727
  default: return null
713
728
  }
714
729
  }
@@ -1,12 +1,12 @@
1
1
  // This file is autogenerated by the hyperschema compiler
2
- // Schema Version: 8
2
+ // Schema Version: 9
3
3
  /* eslint-disable camelcase */
4
4
  /* eslint-disable quotes */
5
5
  /* eslint-disable space-before-function-paren */
6
6
 
7
7
  import { c } from 'hyperschema/runtime'
8
8
 
9
- const VERSION = 8
9
+ const VERSION = 9
10
10
 
11
11
  // eslint-disable-next-line no-unused-vars
12
12
  let version = VERSION
@@ -478,7 +478,8 @@ const encoding11 = {
478
478
  ((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
479
479
  ((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
480
480
  ((version >= 5 && m.payload) ? 8388608 : 0) |
481
- ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
481
+ ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
482
+ ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
482
483
 
483
484
  encoding10.preencode(state, m.type)
484
485
  c.uint.preencode(state, flags)
@@ -533,7 +534,8 @@ const encoding11 = {
533
534
  ((version >= 5 && m.grantedDirs) ? 2097152 : 0) |
534
535
  ((version >= 5 && m.grantedDrives) ? 4194304 : 0) |
535
536
  ((version >= 5 && m.payload) ? 8388608 : 0) |
536
- ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0)
537
+ ((version >= 5 && m.grantedWriteDirs) ? 16777216 : 0) |
538
+ ((version >= 9 && m.captureInferenceCalls) ? 33554432 : 0)
537
539
 
538
540
  encoding10.encode(state, m.type)
539
541
  c.uint.encode(state, flags)
@@ -592,7 +594,8 @@ const encoding11 = {
592
594
  grantedDirs: (version >= 5 && (flags & 2097152) !== 0) ? encoding11_22.decode(state) : null,
593
595
  grantedDrives: (version >= 5 && (flags & 4194304) !== 0) ? encoding11_23.decode(state) : null,
594
596
  payload: (version >= 5 && (flags & 8388608) !== 0) ? c.json.decode(state) : null,
595
- grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null
597
+ grantedWriteDirs: (version >= 5 && (flags & 16777216) !== 0) ? encoding11_25.decode(state) : null,
598
+ captureInferenceCalls: (version >= 9 && (flags & 33554432) !== 0)
596
599
  }
597
600
  }
598
601
  }
@@ -613,13 +616,15 @@ const encoding12_enum = {
613
616
  "question-ask": 'question-ask',
614
617
  done: 'done',
615
618
  "tool-activity": 'tool-activity',
616
- "drive-ask": 'drive-ask'
619
+ "drive-ask": 'drive-ask',
620
+ "inference-call": 'inference-call',
621
+ "inference-sent": 'inference-sent'
617
622
  }
618
623
 
619
624
  // @harness/completion-event-type enum
620
625
  const encoding12 = {
621
626
  preencode (state, m) {
622
- state.end++ // max enum is 16 so always one byte
627
+ state.end++ // max enum is 18 so always one byte
623
628
  },
624
629
  encode (state, m) {
625
630
  switch (m) {
@@ -671,6 +676,12 @@ const encoding12 = {
671
676
  case 'drive-ask':
672
677
  c.uint.encode(state, 16)
673
678
  break
679
+ case 'inference-call':
680
+ c.uint.encode(state, 17)
681
+ break
682
+ case 'inference-sent':
683
+ c.uint.encode(state, 18)
684
+ break
674
685
  default:
675
686
  throw new Error('Unknown enum')
676
687
  }
@@ -709,6 +720,10 @@ const encoding12 = {
709
720
  return 'tool-activity'
710
721
  case 16:
711
722
  return 'drive-ask'
723
+ case 17:
724
+ return 'inference-call'
725
+ case 18:
726
+ return 'inference-sent'
712
727
  default: return null
713
728
  }
714
729
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": 8,
2
+ "version": 9,
3
3
  "schema": [
4
4
  {
5
5
  "name": "empty",
@@ -446,6 +446,11 @@
446
446
  "array": true,
447
447
  "type": "string",
448
448
  "version": 5
449
+ },
450
+ {
451
+ "name": "captureInferenceCalls",
452
+ "type": "bool",
453
+ "version": 9
449
454
  }
450
455
  ]
451
456
  },
@@ -517,6 +522,14 @@
517
522
  {
518
523
  "key": "drive-ask",
519
524
  "version": 5
525
+ },
526
+ {
527
+ "key": "inference-call",
528
+ "version": 9
529
+ },
530
+ {
531
+ "key": "inference-sent",
532
+ "version": 9
520
533
  }
521
534
  ],
522
535
  "strings": true
@@ -1,5 +1,5 @@
1
1
  // This file is autogenerated by hyperschema-ts
2
- // Schema version: 8
2
+ // Schema version: 9
3
3
  // Do not edit manually.
4
4
 
5
5
  export interface HarnessEmpty {
@@ -86,9 +86,10 @@ export interface HarnessCompletionFrame {
86
86
  grantedDrives?: HarnessGrantedDrive[] | null
87
87
  payload?: unknown | null
88
88
  grantedWriteDirs?: string[] | null
89
+ captureInferenceCalls?: boolean
89
90
  }
90
91
 
91
- export type HarnessCompletionEventType = "content" | "thinking" | "tool-call" | "tool-result" | "approval-ask" | "metrics" | "error" | "aborted" | "attach-ask" | "fetch-ask" | "progress" | "rag-ask" | "question-ask" | "done" | "tool-activity" | "drive-ask"
92
+ export type HarnessCompletionEventType = "content" | "thinking" | "tool-call" | "tool-result" | "approval-ask" | "metrics" | "error" | "aborted" | "attach-ask" | "fetch-ask" | "progress" | "rag-ask" | "question-ask" | "done" | "tool-activity" | "drive-ask" | "inference-call" | "inference-sent"
92
93
 
93
94
  export interface HarnessCompletionEvent {
94
95
  type: HarnessCompletionEventType
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qvac/harness",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "type": "module",
5
5
  "description": "An AI harness implementing generate(context) via @qvac/sdk. Knows nothing about workbench, hyperdb, or chunks — just inference in, events out.",
6
6
  "exports": {
@@ -539,16 +539,28 @@
539
539
  "./lib/tools/url-guard.ts": {
540
540
  "types": "./dist-lib/lib/tools/url-guard.d.ts",
541
541
  "default": "./dist-lib/lib/tools/url-guard.js"
542
+ },
543
+ "./lib/tools/weather-lookup.ts": {
544
+ "types": "./dist-lib/lib/tools/weather-lookup.d.ts",
545
+ "default": "./dist-lib/lib/tools/weather-lookup.js"
546
+ },
547
+ "./lib/tools/weather-lookup/place.ts": {
548
+ "types": "./dist-lib/lib/tools/weather-lookup/place.d.ts",
549
+ "default": "./dist-lib/lib/tools/weather-lookup/place.js"
550
+ },
551
+ "./lib/tools/weather-lookup/report.ts": {
552
+ "types": "./dist-lib/lib/tools/weather-lookup/report.d.ts",
553
+ "default": "./dist-lib/lib/tools/weather-lookup/report.js"
542
554
  }
543
555
  },
544
556
  "scripts": {
545
557
  "build:schema": "bare schema/build.ts",
546
- "test": "npm run vendor:wheels && npm run test:node && npm run test:bare && npm run test:addons",
547
- "test:node": "QVAC_NO_SKILL_BIN_PROBE=1 brittle-node test/all.ts | prettytap",
548
- "test:bare": "QVAC_NO_SKILL_BIN_PROBE=1 brittle-bare test/all.ts | prettytap",
558
+ "test": "npm run vendor:wheels && npm run test:bare && npm run test:addons",
559
+ "test:bare": "QVAC_NO_SKILL_BIN_PROBE=1 prettytap -- brittle-bare test/all.ts",
549
560
  "format": "prettier . --write",
550
561
  "lint": "prettier . --check && lunte && tsc --noEmit",
551
562
  "build:bundle": "node scripts/build-bundle.mjs",
563
+ "skill-eval": "bare examples/skill-eval/run.ts",
552
564
  "prepack": "node scripts/vendor-python-wheels.mjs && node scripts/build-lib.mjs && node scripts/build-bundle.mjs --minify",
553
565
  "vendor:wheels": "node scripts/vendor-python-wheels.mjs",
554
566
  "build:lib": "node scripts/build-lib.mjs",
@@ -639,7 +651,7 @@
639
651
  "dependencies": {
640
652
  "@qvac/inference": "0.19.0",
641
653
  "@qvac/sdk": "0.19.0",
642
- "@qvac/skills": "^0.1.3",
654
+ "@qvac/skills": "^0.1.4",
643
655
  "asenion": "^0.1.0",
644
656
  "b4a": "^1.8.1",
645
657
  "bare-abort-controller": "^1.1.2",
@@ -701,9 +713,9 @@
701
713
  "lunte": "^1.8.3",
702
714
  "prettier": "^3.6.2",
703
715
  "prettier-config-holepunch": "^2.0.0",
704
- "prettytap": "^0.1.3",
716
+ "prettytap": "^0.2.0",
705
717
  "terser": "^5.51.2",
706
- "typescript": "^5.9.3"
718
+ "typescript": "^7.0.2"
707
719
  },
708
720
  "patchedDependencies": {
709
721
  "pyodide@314.0.2": "patches/pyodide@314.0.2.patch",
@@ -711,7 +723,8 @@
711
723
  "localwatch@1.4.3": "patches/localwatch@1.4.3.patch",
712
724
  "hypercore-blob-server@1.15.0": "patches/hypercore-blob-server@1.15.0.patch",
713
725
  "bare-stow@0.1.5": "patches/bare-stow@0.1.5.patch",
714
- "@qvac/inference@0.19.0": "patches/@qvac%2Finference@0.19.0.patch"
726
+ "@qvac/inference@0.19.0": "patches/@qvac%2Finference@0.19.0.patch",
727
+ "brittle@4.1.0": "patches/brittle@4.1.0.patch"
715
728
  },
716
729
  "repository": {
717
730
  "type": "git",
@@ -31,6 +31,7 @@ import { createReadFilesTool } from '../dist-lib/lib/tools/read-files.js'
31
31
  import { createSkillTool } from '../dist-lib/lib/tools/skill.js'
32
32
  import { ensureBundledSkillsDir } from '../dist-lib/lib/tools/skills/bundled-dir.js'
33
33
  import { credentialAllowListFor, mcpReadMethods } from '../dist-lib/lib/tools/skills/index.js'
34
+ import { createWeatherLookupTool } from '../dist-lib/lib/tools/weather-lookup.js'
34
35
  import { createWebFetchTool } from '../dist-lib/lib/tools/web-fetch.js'
35
36
  import { createWebSearchTool } from '../dist-lib/lib/tools/web-search.js'
36
37
 
@@ -137,6 +138,7 @@ export default async function start(ipc, ready) {
137
138
  mcpCallTool,
138
139
  createWebSearchTool(),
139
140
  createWebFetchTool(),
141
+ createWeatherLookupTool(),
140
142
  createReadFilesTool({ deniedRoots }),
141
143
  createFileGlobTool({ deniedRoots }),
142
144
  createGrepTool({ deniedRoots }),
@@ -1,86 +0,0 @@
1
- ---
2
- name: asana
3
- description: Conventions for the QVAC Assistant Asana board when working through the Asana MCP server — what the MCP cannot do and what that silently breaks, the Context field that decides whether a task is visible at all, and the rule against consuming task descriptions. Use before creating, moving, or reading any Asana task for this project.
4
- ---
5
-
6
- # Asana — QVAC Assistant board
7
-
8
- Asana work here goes through the **Asana MCP server**. This skill is not a tool;
9
- it is the handful of things the MCP does not tell you and will not stop you
10
- getting wrong.
11
-
12
- - Workspace `45238840754660` (tether.to)
13
- - Project `1214754188814246` (QVAC Assistant)
14
- - Board: <https://app.asana.com/1/45238840754660/project/1214754188814246>
15
-
16
- ## Do not create tasks through the MCP
17
-
18
- `asana_create_task` takes `resource_subtype` of only `default_task`, `milestone`
19
- or `approval`, and neither it nor `asana_update_task` accepts `custom_type` or
20
- `custom_type_status_option`. This board runs on the **QVAC Basic Task** custom
21
- type (`1214533632534265`), whose status options _are_ the workflow — the project
22
- has one real section and tracks status entirely through the custom type.
23
-
24
- So an MCP-created task is a plain default task that:
25
-
26
- - is not a `QVAC Basic Task`,
27
- - has no status (To Do / In Progress / In Code Review / Blocked /
28
- Completed-Ready for QA / Fully Verified / Closed-Won't Fix), and
29
- - cannot be given one afterwards through the API.
30
-
31
- It lands on the board looking almost right and is undriveable. **Ask the user to
32
- create the task in the Asana UI**, where the custom type is the default, and then
33
- use the MCP to fill fields or comment on it. Do not create it yourself and
34
- promise to "fix the type later" — the API has no route to do that.
35
-
36
- Moving a task's status has the same limitation: the status lives on
37
- `custom_type_status_option`, which the MCP cannot set. Status changes are a UI
38
- action.
39
-
40
- ## Context is mandatory, and the MCP will not warn you
41
-
42
- The project's Dev Board tabs are saved views filtered on the **Context** custom
43
- field. A task with Context unset appears only in "Full List" and "Overview" — it
44
- is invisible on every Dev Board tab and silently slips off the team's radar.
45
-
46
- Whenever you set fields on a task, set Context. Field `1214754188814251`:
47
-
48
- | Value | GID | For |
49
- | -------------- | ------------------ | ------------------------------------------------- |
50
- | `harness` | `1214754188814252` | engine, mesh and sync, storage, build and release |
51
- | `integrations` | `1214754188814253` | assistant runtime, agents, tools, skills |
52
- | `other` | `1214758268571416` | genuinely cross-cutting: org, legal, product docs |
53
-
54
- Surface which one you picked and why, and let the user correct it. Never guess
55
- silently, and never leave it blank to avoid choosing.
56
-
57
- ## Release grouping
58
-
59
- Each Dev Board tab groups by **QVAC Workbench Release** (field
60
- `1214111405360914`) first. A task with none lands in an "Untitled" bucket at the
61
- bottom of every tab. Default to `tbc` (`1214757840453965`) when the release is
62
- undecided.
63
-
64
- **That field is the app's release, not a package version.** `@qvac/harness`,
65
- `@qvac/core` and `@qvac/skills` each ship their own `0.x` line; putting one of
66
- those numbers here files the task against a release that does not exist.
67
-
68
- ## Never consume task descriptions
69
-
70
- Work from task metadata only: GID, name, permalink, completion state, assignee,
71
- memberships, custom fields, custom type and status, timestamps, and comments.
72
-
73
- - `asana_get_task` returns the description by default. Pass an explicit
74
- `opt_fields` list that omits `notes`, `html_notes` and `description`.
75
- - Do not use Asana full-text search as a fallback — it matches descriptions.
76
- Find tasks by the QVAC custom field (`1209150993228635`, text) or by GID.
77
- - If the user wants you to act on a description, ask them to paste the relevant
78
- excerpt rather than fetching it.
79
-
80
- ## Before any mutation
81
-
82
- Show the exact change and wait for a yes. That includes field edits, comments and
83
- completion — this board is shared with the whole team, and a comment cannot be
84
- unsent.
85
-
86
- Never put tokens, secrets or internal-only URLs in a task or comment.