@hmharness/agent 0.23.24 → 0.23.26

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.
@@ -1,22 +1,22 @@
1
- /**
2
- * @hmharness/agent - Code World Model recorder (production sensor wiring)
3
- *
4
- * Round 38 closes the loop the sensors were waiting for: extension page
5
- * observations now reach a PERSISTED Code World Model. The recorder is a
6
- * lazy per-home singleton — the first observation loads the model from
7
- * HMH_HOME, the sensor feeds it, and a debounce flushes to disk. The LSP
8
- * sensor (round 35) rides the same store once its tools gain an event
9
- * hook; until then it stays library-only, honestly.
10
- *
11
- * Failure posture: everything best-effort — a storage error logs nothing
12
- * and never breaks the tool that observed the page (evidence must not be
13
- * able to kill the work it evidences). A crash loses at most one debounce
14
- * window of observations.
15
- */
16
1
  import { type CodeWorldModel } from '@hmharness/cognitive';
17
2
  import type { RawPageData } from '@hmharness/extension';
3
+ import type { Tool } from '@hmharness/kernel';
4
+ import { type CodeWorldSyncInput } from './code-wm-sensor.js';
18
5
  /** The onPageRead hook handed to extensionTools — one closure per home. */
19
6
  export declare function pageReadSink(home: string): (raw: RawPageData) => void;
7
+ /** The onObserve hook handed to lspTools — the LSP tools' read-only pulls
8
+ * become durable Code WM evidence, same store, same debounce. */
9
+ export declare function lspObserveSink(home: string): (obs: CodeWorldSyncInput) => void;
10
+ /** Build facts replace (the model keeps only the LATEST build verdict). */
11
+ export declare function buildSink(home: string): (fact: {
12
+ ok: boolean;
13
+ outputDigest?: string;
14
+ }) => void;
15
+ /** Registry-assembly wrapper (round 44): the harmony build tools gain a
16
+ * build-fact observation without the domain package learning about
17
+ * cognitive. The wrap never alters the tool's result; a sink error is
18
+ * swallowed (the observation must not fail the work it evidences). */
19
+ export declare function observeBuildTools(tools: Tool[], home: string): Tool[];
20
20
  /** Test isolation: drop caches + pending timers (never used in production). */
21
21
  export declare function resetCodeWorldRecorder(): void;
22
22
  /** Introspection for tests/status surfaces: the live model for a home. */
@@ -1,29 +1,74 @@
1
1
  /**
2
2
  * @hmharness/agent - Code World Model recorder (production sensor wiring)
3
3
  *
4
- * Round 38 closes the loop the sensors were waiting for: extension page
5
- * observations now reach a PERSISTED Code World Model. The recorder is a
6
- * lazy per-home singleton — the first observation loads the model from
7
- * HMH_HOME, the sensor feeds it, and a debounce flushes to disk. The LSP
8
- * sensor (round 35) rides the same store once its tools gain an event
9
- * hook; until then it stays library-only, honestly.
4
+ * Round 38 closed the loop for extension page observations; round 43 adds
5
+ * the LSP side (lspTools onObserve → symbols/diagnostics); round 44 adds
6
+ * the build side: the harmony build tools' results become the model's
7
+ * LATEST BuildFact, wrapped at registry assembly so the domain package
8
+ * stays single-minded (kernel-only deps — the audit's composition-layer
9
+ * rule). All three families share the lazy per-home singleton and one
10
+ * debounced flush. LiveCodeWmSensor remains the wrapper for callers that
11
+ * own a client and want file-driven syncs; the tool-hook paths share the
12
+ * ingestion core.
10
13
  *
11
14
  * Failure posture: everything best-effort — a storage error logs nothing
12
15
  * and never breaks the tool that observed the page (evidence must not be
13
16
  * able to kill the work it evidences). A crash loses at most one debounce
14
17
  * window of observations.
15
18
  */
19
+ import { createHash } from 'node:crypto';
16
20
  import { loadCodeWorldModel, saveCodeWorldModel } from '@hmharness/cognitive';
17
21
  import { syncExtensionRuntime } from "./extension-wm-sensor.js";
22
+ import { syncCodeWorldModel } from "./code-wm-sensor.js";
18
23
  const SAVE_DEBOUNCE_MS = 2_000;
19
24
  const entries = new Map();
20
25
  /** The onPageRead hook handed to extensionTools — one closure per home. */
21
26
  export function pageReadSink(home) {
22
27
  return (raw) => {
23
- void observe(home, raw);
28
+ void mutate(home, (cwm) => syncExtensionRuntime(cwm, raw));
24
29
  };
25
30
  }
26
- async function observe(home, raw) {
31
+ /** The onObserve hook handed to lspTools — the LSP tools' read-only pulls
32
+ * become durable Code WM evidence, same store, same debounce. */
33
+ export function lspObserveSink(home) {
34
+ return (obs) => {
35
+ if (!obs.symbols?.length && !obs.diagnostics?.length)
36
+ return;
37
+ void mutate(home, (cwm) => syncCodeWorldModel(cwm, obs));
38
+ };
39
+ }
40
+ /** Build facts replace (the model keeps only the LATEST build verdict). */
41
+ export function buildSink(home) {
42
+ return (fact) => {
43
+ void mutate(home, (cwm) => cwm.ingest({ build: { ok: fact.ok, ...(fact.outputDigest ? { outputDigest: fact.outputDigest } : {}), at: new Date().toISOString() } }));
44
+ };
45
+ }
46
+ /** Registry-assembly wrapper (round 44): the harmony build tools gain a
47
+ * build-fact observation without the domain package learning about
48
+ * cognitive. The wrap never alters the tool's result; a sink error is
49
+ * swallowed (the observation must not fail the work it evidences). */
50
+ export function observeBuildTools(tools, home) {
51
+ const sink = buildSink(home);
52
+ return tools.map((t) => {
53
+ if (t.name !== 'harmony_build' && t.name !== 'harmony_cjpm_build')
54
+ return t;
55
+ const orig = t.execute.bind(t);
56
+ const wrapped = {
57
+ ...t,
58
+ async execute(args, ctx) {
59
+ const r = await orig(args, ctx);
60
+ try {
61
+ const out = typeof r.output === 'string' ? r.output : '';
62
+ sink({ ok: !r.isError, ...(out ? { outputDigest: createHash('sha256').update(out).digest('hex').slice(0, 16) } : {}) });
63
+ }
64
+ catch { /* observation must never fail the tool */ }
65
+ return r;
66
+ },
67
+ };
68
+ return wrapped;
69
+ });
70
+ }
71
+ async function mutate(home, fn) {
27
72
  try {
28
73
  let entry = entries.get(home);
29
74
  if (!entry) {
@@ -31,7 +76,7 @@ async function observe(home, raw) {
31
76
  entries.set(home, entry);
32
77
  }
33
78
  const cwm = await entry.load;
34
- syncExtensionRuntime(cwm, raw);
79
+ fn(cwm);
35
80
  entry.dirty = true;
36
81
  if (!entry.timer) {
37
82
  entry.timer = setTimeout(() => {
package/dist/runner.js CHANGED
@@ -18,7 +18,7 @@ import { opsTools } from '@hmharness/domain-ops';
18
18
  import { discoverServers, lspTools } from '@hmharness/lsp';
19
19
  import { discoverBrowsers, browserTools } from '@hmharness/browser';
20
20
  import { discoverExtensionBridgeSync, extensionTools } from '@hmharness/extension';
21
- import { pageReadSink } from "./code-wm-recorder.js";
21
+ import { pageReadSink, lspObserveSink, observeBuildTools } from "./code-wm-recorder.js";
22
22
  import * as readline from 'node:readline/promises';
23
23
  import { stdin } from 'node:process';
24
24
  import { baseTools } from "./tools.js";
@@ -39,7 +39,7 @@ export function toServerConfig(c) {
39
39
  export const spawnBase = {};
40
40
  export function nativeRegistry(depth, opts = {}) {
41
41
  const reg = new Registry();
42
- reg.registerAll(baseTools).registerAll(harmonyTools).registerAll(opsTools);
42
+ reg.registerAll(baseTools).registerAll(observeBuildTools(harmonyTools, homeDir())).registerAll(opsTools);
43
43
  // W6: LSP Tier-0 code-intelligence tools — registered ONLY when a real
44
44
  // server is discoverable on PATH; a machine with no language servers
45
45
  // must not carry dead tools. Discovery is synchronous (memoized PATH
@@ -49,7 +49,11 @@ export function nativeRegistry(depth, opts = {}) {
49
49
  // healthy-only: a PATH shim whose toolchain lacks the component would
50
50
  // register a tool that always errors — skip it, keep the registry honest
51
51
  if (discoverServers().some((s) => s.healthy)) {
52
- reg.registerAll(lspTools({ workspaceRoot: opts.workspaceRoot ?? process.cwd(), home: homeDir() }));
52
+ // onObserve feeds the PERSISTED Code World Model (round 43): every
53
+ // lsp_symbols/lsp_diagnostics pull becomes durable entity/relation/
54
+ // diagnostic evidence — best-effort, same store as the extension
55
+ // recorder, never able to fail the tool that observed.
56
+ reg.registerAll(lspTools({ workspaceRoot: opts.workspaceRoot ?? process.cwd(), home: homeDir(), onObserve: lspObserveSink(homeDir()) }));
53
57
  }
54
58
  }
55
59
  catch { /* lsp optional: never block tool assembly */ }
package/package.json CHANGED
@@ -1,40 +1,40 @@
1
- {
2
- "name": "@hmharness/agent",
3
- "version": "0.23.24",
4
- "description": "hmharness agent execution layer: base tools, system prompt, sub-agent spawn, and the shared task runner that frontends (cli, web) drive.",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "default": "./dist/index.js"
12
- }
13
- },
14
- "scripts": {
15
- "build": "tsc -p tsconfig.build.json"
16
- },
17
- "dependencies": {
18
- "@hmharness/cognitive": "0.23.24",
19
- "@hmharness/domain-harmony": "0.23.24",
20
- "@hmharness/domain-ops": "0.23.24",
21
- "@hmharness/evolution": "0.23.24",
22
- "@hmharness/kernel": "0.23.24",
23
- "@hmharness/observability": "0.23.24",
24
- "@hmharness/sandbox": "0.23.24",
25
- "@hmharness/lsp": "0.23.24",
26
- "@hmharness/browser": "0.23.24",
27
- "@hmharness/extension": "0.23.24"
28
- },
29
- "files": [
30
- "dist"
31
- ],
32
- "license": "MIT",
33
- "repository": {
34
- "type": "git",
35
- "url": "git+https://github.com/swsgbl/hmharness.git"
36
- },
37
- "engines": {
38
- "node": ">=22"
39
- }
40
- }
1
+ {
2
+ "name": "@hmharness/agent",
3
+ "version": "0.23.26",
4
+ "description": "hmharness agent execution layer: base tools, system prompt, sub-agent spawn, and the shared task runner that frontends (cli, web) drive.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ }
13
+ },
14
+ "scripts": {
15
+ "build": "tsc -p tsconfig.build.json"
16
+ },
17
+ "dependencies": {
18
+ "@hmharness/cognitive": "0.23.26",
19
+ "@hmharness/domain-harmony": "0.23.26",
20
+ "@hmharness/domain-ops": "0.23.26",
21
+ "@hmharness/evolution": "0.23.26",
22
+ "@hmharness/kernel": "0.23.26",
23
+ "@hmharness/observability": "0.23.26",
24
+ "@hmharness/sandbox": "0.23.26",
25
+ "@hmharness/lsp": "0.23.26",
26
+ "@hmharness/browser": "0.23.26",
27
+ "@hmharness/extension": "0.23.26"
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/swsgbl/hmharness.git"
36
+ },
37
+ "engines": {
38
+ "node": ">=22"
39
+ }
40
+ }