@pelotto-tech/bellwether 0.0.0 → 0.1.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 (114) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +228 -1
  3. package/dist/agents/claude.d.ts +8 -0
  4. package/dist/agents/claude.js +63 -0
  5. package/dist/agents/claude.js.map +1 -0
  6. package/dist/agents/copilot.d.ts +7 -0
  7. package/dist/agents/copilot.js +39 -0
  8. package/dist/agents/copilot.js.map +1 -0
  9. package/dist/agents/index.d.ts +5 -0
  10. package/dist/agents/index.js +8 -0
  11. package/dist/agents/index.js.map +1 -0
  12. package/dist/agents/paths.d.ts +2 -0
  13. package/dist/agents/paths.js +5 -0
  14. package/dist/agents/paths.js.map +1 -0
  15. package/dist/agents/types.d.ts +29 -0
  16. package/dist/agents/types.js +2 -0
  17. package/dist/agents/types.js.map +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.js +4 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/install.d.ts +38 -0
  22. package/dist/install.js +104 -0
  23. package/dist/install.js.map +1 -0
  24. package/dist/json-file.d.ts +12 -0
  25. package/dist/json-file.js +33 -0
  26. package/dist/json-file.js.map +1 -0
  27. package/dist/main.d.ts +2 -0
  28. package/dist/main.js +75 -0
  29. package/dist/main.js.map +1 -0
  30. package/dist/roles.d.ts +3 -0
  31. package/dist/roles.js +13 -0
  32. package/dist/roles.js.map +1 -0
  33. package/dist/run.d.ts +9 -0
  34. package/dist/run.js +41 -0
  35. package/dist/run.js.map +1 -0
  36. package/dist/skill.d.ts +9 -0
  37. package/dist/skill.js +65 -0
  38. package/dist/skill.js.map +1 -0
  39. package/package.json +53 -6
  40. package/runtime/adapter/dist/actions.d.ts +15 -0
  41. package/runtime/adapter/dist/actions.js +7 -0
  42. package/runtime/adapter/dist/actions.js.map +1 -0
  43. package/runtime/adapter/dist/bin.d.ts +2 -0
  44. package/runtime/adapter/dist/bin.js +121 -0
  45. package/runtime/adapter/dist/bin.js.map +1 -0
  46. package/runtime/adapter/dist/config.d.ts +41 -0
  47. package/runtime/adapter/dist/config.js +71 -0
  48. package/runtime/adapter/dist/config.js.map +1 -0
  49. package/runtime/adapter/dist/core.d.ts +8 -0
  50. package/runtime/adapter/dist/core.js +10 -0
  51. package/runtime/adapter/dist/core.js.map +1 -0
  52. package/runtime/adapter/dist/herdr/connection.d.ts +34 -0
  53. package/runtime/adapter/dist/herdr/connection.js +137 -0
  54. package/runtime/adapter/dist/herdr/connection.js.map +1 -0
  55. package/runtime/adapter/dist/herdr/index.d.ts +5 -0
  56. package/runtime/adapter/dist/herdr/index.js +5 -0
  57. package/runtime/adapter/dist/herdr/index.js.map +1 -0
  58. package/runtime/adapter/dist/herdr/mapper.d.ts +27 -0
  59. package/runtime/adapter/dist/herdr/mapper.js +141 -0
  60. package/runtime/adapter/dist/herdr/mapper.js.map +1 -0
  61. package/runtime/adapter/dist/herdr/paths.d.ts +29 -0
  62. package/runtime/adapter/dist/herdr/paths.js +89 -0
  63. package/runtime/adapter/dist/herdr/paths.js.map +1 -0
  64. package/runtime/adapter/dist/herdr/protocol.d.ts +102 -0
  65. package/runtime/adapter/dist/herdr/protocol.js +19 -0
  66. package/runtime/adapter/dist/herdr/protocol.js.map +1 -0
  67. package/runtime/adapter/dist/herdr/source.d.ts +99 -0
  68. package/runtime/adapter/dist/herdr/source.js +316 -0
  69. package/runtime/adapter/dist/herdr/source.js.map +1 -0
  70. package/runtime/adapter/dist/index.d.ts +6 -0
  71. package/runtime/adapter/dist/index.js +7 -0
  72. package/runtime/adapter/dist/index.js.map +1 -0
  73. package/runtime/adapter/dist/mock.d.ts +33 -0
  74. package/runtime/adapter/dist/mock.js +130 -0
  75. package/runtime/adapter/dist/mock.js.map +1 -0
  76. package/runtime/adapter/dist/random.d.ts +3 -0
  77. package/runtime/adapter/dist/random.js +18 -0
  78. package/runtime/adapter/dist/random.js.map +1 -0
  79. package/runtime/adapter/dist/recording.d.ts +22 -0
  80. package/runtime/adapter/dist/recording.js +52 -0
  81. package/runtime/adapter/dist/recording.js.map +1 -0
  82. package/runtime/adapter/dist/roles.d.ts +16 -0
  83. package/runtime/adapter/dist/roles.js +21 -0
  84. package/runtime/adapter/dist/roles.js.map +1 -0
  85. package/runtime/adapter/dist/rollup.d.ts +5 -0
  86. package/runtime/adapter/dist/rollup.js +18 -0
  87. package/runtime/adapter/dist/rollup.js.map +1 -0
  88. package/runtime/adapter/dist/scrub.d.ts +9 -0
  89. package/runtime/adapter/dist/scrub.js +56 -0
  90. package/runtime/adapter/dist/scrub.js.map +1 -0
  91. package/runtime/adapter/dist/server.d.ts +47 -0
  92. package/runtime/adapter/dist/server.js +119 -0
  93. package/runtime/adapter/dist/server.js.map +1 -0
  94. package/runtime/adapter/dist/source.d.ts +20 -0
  95. package/runtime/adapter/dist/source.js +14 -0
  96. package/runtime/adapter/dist/source.js.map +1 -0
  97. package/runtime/adapter/dist/types.d.ts +66 -0
  98. package/runtime/adapter/dist/types.js +23 -0
  99. package/runtime/adapter/dist/types.js.map +1 -0
  100. package/runtime/adapter/dist/world.d.ts +9 -0
  101. package/runtime/adapter/dist/world.js +64 -0
  102. package/runtime/adapter/dist/world.js.map +1 -0
  103. package/runtime/adapter/package.json +37 -0
  104. package/runtime/renderer/dist/assets/BitmapFont-CrMu5gVf.js +6 -0
  105. package/runtime/renderer/dist/assets/CanvasRenderer-BJUwGe2K.js +1 -0
  106. package/runtime/renderer/dist/assets/Filter-CYMWP98C.js +1 -0
  107. package/runtime/renderer/dist/assets/RenderTargetSystem-CUv6yCH8.js +184 -0
  108. package/runtime/renderer/dist/assets/WebGLRenderer-DT-aSeEc.js +156 -0
  109. package/runtime/renderer/dist/assets/WebGPURenderer-CV0poHB6.js +75 -0
  110. package/runtime/renderer/dist/assets/browserAll-BpE2Jy31.js +14 -0
  111. package/runtime/renderer/dist/assets/getTexelRangeRects-BCdgu8cV.js +195 -0
  112. package/runtime/renderer/dist/assets/index-BgIYSiaY.js +296 -0
  113. package/runtime/renderer/dist/assets/webworkerAll-DEtPMT-J.js +83 -0
  114. package/runtime/renderer/dist/index.html +36 -0
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import { createSource, loadSourceConfig } from './config.js';
4
+ import { MockSource } from './mock.js';
5
+ import { recordTo, ReplaySource } from './recording.js';
6
+ import { scrubDelta, scrubFile } from './scrub.js';
7
+ import { DEFAULT_PORT, DELTA_PATH, DeltaServer } from './server.js';
8
+ const USAGE = `bellwether-adapter: stream Herdr world deltas over WebSocket
9
+
10
+ Source (default from bellwether.toml / BELLWETHER_SOURCE, else mock):
11
+ --live read the live Herdr TUI socket API
12
+ --mock generate mock agents
13
+ --replay <file> replay a recorded .jsonl (loops)
14
+ --session <name> live: one named session --all live: every running session
15
+ --socket <path> live: explicit socket/pipe path
16
+ --config <file> config file (default bellwether.toml)
17
+ --seed <n> mock seed (default 1)
18
+ --interval <ms> mock delta interval (default 1500)
19
+ --speed <n> replay speed multiplier (default 1)
20
+
21
+ Output:
22
+ --port <n> WebSocket port (default ${DEFAULT_PORT}); deltas on ${DELTA_PATH}
23
+ --serve <dir> also serve a built renderer from <dir>
24
+ --record <file> append every delta to a .jsonl file
25
+ --scrub with --record: hash repo/branch/workspace labels, strip say text and titles
26
+ --scrub-file <in> <out> scrub an existing .jsonl recording and exit
27
+ --actions let the overlay send prompts and keys to agents (focus is always allowed)
28
+ --pack <name> skin pack for the served overlay (default from bellwether.toml, else neutral)
29
+ --print print every delta to stdout as JSON lines
30
+ -h, --help`;
31
+ const { values, positionals } = parseArgs({
32
+ options: {
33
+ live: { type: 'boolean' },
34
+ mock: { type: 'boolean' },
35
+ replay: { type: 'string' },
36
+ session: { type: 'string' },
37
+ all: { type: 'boolean' },
38
+ socket: { type: 'string' },
39
+ config: { type: 'string' },
40
+ seed: { type: 'string' },
41
+ interval: { type: 'string' },
42
+ speed: { type: 'string' },
43
+ port: { type: 'string' },
44
+ serve: { type: 'string' },
45
+ record: { type: 'string' },
46
+ scrub: { type: 'boolean' },
47
+ actions: { type: 'boolean' },
48
+ 'scrub-file': { type: 'string' },
49
+ print: { type: 'boolean' },
50
+ pack: { type: 'string' },
51
+ help: { type: 'boolean', short: 'h' },
52
+ },
53
+ allowPositionals: true,
54
+ });
55
+ let scrubConfig = false;
56
+ let actionsConfig = false;
57
+ let clientPack = values.pack;
58
+ if (values.help) {
59
+ console.log(USAGE);
60
+ process.exit(0);
61
+ }
62
+ if (values['scrub-file']) {
63
+ const out = positionals[0];
64
+ if (!out) {
65
+ process.stderr.write('usage: --scrub-file <in.jsonl> <out.jsonl>\n');
66
+ process.exit(1);
67
+ }
68
+ const n = scrubFile(values['scrub-file'], out);
69
+ process.stderr.write(`bellwether-adapter: scrubbed ${n} deltas into ${out}\n`);
70
+ process.exit(0);
71
+ }
72
+ const log = (m) => process.stderr.write(m + '\n');
73
+ async function pickSource() {
74
+ if (values.replay) {
75
+ return ReplaySource.fromFile(values.replay, { speed: Number(values.speed ?? 1), loop: true });
76
+ }
77
+ const cfg = await loadSourceConfig(values.config ?? 'bellwether.toml');
78
+ if (values.pack)
79
+ cfg.pack = values.pack;
80
+ clientPack = cfg.pack ?? clientPack;
81
+ scrubConfig = cfg.scrub ?? false;
82
+ actionsConfig = cfg.actions ?? false;
83
+ if (values.live)
84
+ cfg.source = 'live';
85
+ if (values.mock)
86
+ cfg.source = 'mock';
87
+ if (values.session)
88
+ cfg.herdr.sessions = [values.session];
89
+ if (values.all)
90
+ cfg.herdr.sessions = 'all';
91
+ if (values.socket)
92
+ cfg.herdr.socket = values.socket;
93
+ log(`bellwether-adapter: source=${cfg.source}`);
94
+ return createSource(cfg, {
95
+ log,
96
+ mock: () => new MockSource({ seed: Number(values.seed ?? 1), intervalMs: Number(values.interval ?? 1500) }),
97
+ });
98
+ }
99
+ const source = await pickSource();
100
+ const server = new DeltaServer({ port: Number(values.port ?? DEFAULT_PORT), staticDir: values.serve, clientConfig: clientPack ? { pack: clientPack } : {}, actions: values.actions || actionsConfig, log });
101
+ server.attach(source);
102
+ if (values.record) {
103
+ const rec = recordTo(values.record);
104
+ const scrubOn = values.scrub || scrubConfig;
105
+ source.on('delta', scrubOn ? (d) => rec(scrubDelta(d)) : rec);
106
+ }
107
+ if (values.print)
108
+ source.on('delta', (d) => process.stdout.write(JSON.stringify(d) + '\n'));
109
+ const port = await server.listen();
110
+ await source.start();
111
+ log(`bellwether-adapter: deltas on ws://127.0.0.1:${port}${DELTA_PATH}`);
112
+ if (values.serve)
113
+ log(`bellwether-adapter: overlay at http://127.0.0.1:${port}/`);
114
+ const shutdown = async () => {
115
+ await source.stop();
116
+ await server.close();
117
+ process.exit(0);
118
+ };
119
+ process.on('SIGINT', shutdown);
120
+ process.on('SIGTERM', shutdown);
121
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { WorldSource } from './source.js';
2
+ export type SourceKind = 'mock' | 'live';
3
+ export interface SourceConfig {
4
+ source: SourceKind;
5
+ /** Skin pack the overlay shows (a folder name under themes/). The renderer falls back to neutral if it is unknown. */
6
+ pack?: string;
7
+ /** Scrub recordings at record time (`scrub = true`). */
8
+ scrub?: boolean;
9
+ /** Let the overlay send prompts and keys to agents (`actions = true`). Focus is always allowed. */
10
+ actions?: boolean;
11
+ herdr: {
12
+ /** `"all"` discovers running sessions; a list names them; omitted uses HERDR_SESSION or default. */
13
+ sessions?: 'all' | string[];
14
+ socket?: string;
15
+ };
16
+ }
17
+ export declare const DEFAULT_CONFIG: SourceConfig;
18
+ /**
19
+ * Parse the source section of `bellwether.toml`:
20
+ *
21
+ * ```toml
22
+ * source = "live" # or "mock"
23
+ * pack = "aesir" # skin pack: neutral, aesir, wayfarers, or a private theme folder
24
+ * scrub = true # hash labels and strip say text in recordings
25
+ * actions = true # let the overlay prompt and send keys to agents (focus is always on)
26
+ * [herdr]
27
+ * sessions = "all" # or ["default", "overlay-dev"]
28
+ * # socket = "/path/to/herdr.sock"
29
+ * ```
30
+ */
31
+ export declare function parseSourceConfig(text: string): SourceConfig;
32
+ /** Load config from a file (missing file means defaults), then apply env overrides. */
33
+ export declare function loadSourceConfig(file?: string, env?: NodeJS.ProcessEnv): Promise<SourceConfig>;
34
+ export interface CreateSourceDeps {
35
+ log?: (msg: string) => void;
36
+ /** Factories, overridable in tests. */
37
+ live?: (cfg: SourceConfig) => WorldSource;
38
+ mock?: (cfg: SourceConfig) => WorldSource;
39
+ }
40
+ /** Pick the world source named by config. */
41
+ export declare function createSource(cfg: SourceConfig, deps?: CreateSourceDeps): WorldSource;
@@ -0,0 +1,71 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { parse } from 'smol-toml';
3
+ import { HerdrSource } from './herdr/source.js';
4
+ import { MockSource } from './mock.js';
5
+ export const DEFAULT_CONFIG = { source: 'mock', herdr: {} };
6
+ /**
7
+ * Parse the source section of `bellwether.toml`:
8
+ *
9
+ * ```toml
10
+ * source = "live" # or "mock"
11
+ * pack = "aesir" # skin pack: neutral, aesir, wayfarers, or a private theme folder
12
+ * scrub = true # hash labels and strip say text in recordings
13
+ * actions = true # let the overlay prompt and send keys to agents (focus is always on)
14
+ * [herdr]
15
+ * sessions = "all" # or ["default", "overlay-dev"]
16
+ * # socket = "/path/to/herdr.sock"
17
+ * ```
18
+ */
19
+ export function parseSourceConfig(text) {
20
+ const raw = parse(text);
21
+ const source = raw.source ?? DEFAULT_CONFIG.source;
22
+ if (source !== 'mock' && source !== 'live')
23
+ throw new Error(`bellwether.toml: source must be "mock" or "live", got ${JSON.stringify(source)}`);
24
+ const h = (raw.herdr ?? {});
25
+ const herdr = {};
26
+ if (h.sessions !== undefined) {
27
+ if (h.sessions === 'all')
28
+ herdr.sessions = 'all';
29
+ else if (typeof h.sessions === 'string')
30
+ herdr.sessions = [h.sessions];
31
+ else if (Array.isArray(h.sessions) && h.sessions.every((s) => typeof s === 'string'))
32
+ herdr.sessions = h.sessions;
33
+ else
34
+ throw new Error('bellwether.toml: herdr.sessions must be "all", a name, or a list of names');
35
+ }
36
+ if (typeof h.socket === 'string')
37
+ herdr.socket = h.socket;
38
+ if (raw.pack !== undefined && (typeof raw.pack !== 'string' || !/^[a-z0-9][a-z0-9_-]*$/i.test(raw.pack))) {
39
+ throw new Error('bellwether.toml: pack must be a theme folder name');
40
+ }
41
+ if (raw.scrub !== undefined && typeof raw.scrub !== 'boolean')
42
+ throw new Error('bellwether.toml: scrub must be true or false');
43
+ if (raw.actions !== undefined && typeof raw.actions !== 'boolean')
44
+ throw new Error('bellwether.toml: actions must be true or false');
45
+ return { source, ...(raw.actions === true ? { actions: true } : {}), ...(raw.scrub === true ? { scrub: true } : {}), ...(typeof raw.pack === 'string' ? { pack: raw.pack } : {}), herdr };
46
+ }
47
+ /** Load config from a file (missing file means defaults), then apply env overrides. */
48
+ export async function loadSourceConfig(file = 'bellwether.toml', env = process.env) {
49
+ let cfg = { ...DEFAULT_CONFIG, herdr: {} };
50
+ try {
51
+ cfg = parseSourceConfig(await readFile(file, 'utf8'));
52
+ }
53
+ catch (err) {
54
+ if (err.code !== 'ENOENT')
55
+ throw err;
56
+ }
57
+ const override = env.BELLWETHER_SOURCE;
58
+ if (override === 'mock' || override === 'live')
59
+ cfg.source = override;
60
+ if (env.BELLWETHER_PACK && /^[a-z0-9][a-z0-9_-]*$/i.test(env.BELLWETHER_PACK))
61
+ cfg.pack = env.BELLWETHER_PACK;
62
+ return cfg;
63
+ }
64
+ /** Pick the world source named by config. */
65
+ export function createSource(cfg, deps = {}) {
66
+ if (cfg.source === 'live') {
67
+ return deps.live ? deps.live(cfg) : new HerdrSource({ sessions: cfg.herdr.sessions, socket: cfg.herdr.socket, log: deps.log });
68
+ }
69
+ return deps.mock ? deps.mock(cfg) : new MockSource();
70
+ }
71
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export * from './types.js';
2
+ export * from './rollup.js';
3
+ export * from './roles.js';
4
+ export * from './world.js';
5
+ export * from './source.js';
6
+ export * from './actions.js';
7
+ export * from './mock.js';
8
+ export { createRng } from './random.js';
@@ -0,0 +1,10 @@
1
+ // Browser-safe entry: no Node built-ins. The renderer imports from here.
2
+ export * from './types.js';
3
+ export * from './rollup.js';
4
+ export * from './roles.js';
5
+ export * from './world.js';
6
+ export * from './source.js';
7
+ export * from './actions.js';
8
+ export * from './mock.js';
9
+ export { createRng } from './random.js';
10
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import net from 'node:net';
3
+ import type { SuccessResponse } from './protocol.js';
4
+ export declare class HerdrError extends Error {
5
+ readonly code: string;
6
+ constructor(code: string, message: string);
7
+ }
8
+ export type Connector = (connectPath: string) => net.Socket;
9
+ /**
10
+ * One NDJSON connection to a Herdr server socket (Unix socket or Windows named pipe).
11
+ *
12
+ * Events:
13
+ * - `event` (EventLine) pushed lines on a subscription connection
14
+ * - `error` (Error) a request-less error, e.g. `events_lost` on a subscription
15
+ * - `close` () the socket closed
16
+ */
17
+ export declare class HerdrConnection extends EventEmitter {
18
+ private readonly socket;
19
+ private buf;
20
+ private seq;
21
+ private pending;
22
+ private closed;
23
+ private constructor();
24
+ static open(connectPath: string, connector?: Connector, timeoutMs?: number): Promise<HerdrConnection>;
25
+ get isClosed(): boolean;
26
+ request(method: string, params?: Record<string, unknown>, timeoutMs?: number): Promise<SuccessResponse['result']>;
27
+ /** Start a subscription on this connection. Resolves on `subscription_started`. */
28
+ subscribe(subscriptions: Array<Record<string, unknown>>, timeoutMs?: number): Promise<void>;
29
+ close(): void;
30
+ private onData;
31
+ private onLine;
32
+ private failAll;
33
+ private onClose;
34
+ }
@@ -0,0 +1,137 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import net from 'node:net';
3
+ import { isError, isEvent } from './protocol.js';
4
+ export class HerdrError extends Error {
5
+ code;
6
+ constructor(code, message) {
7
+ super(`${code}: ${message}`);
8
+ this.code = code;
9
+ this.name = 'HerdrError';
10
+ }
11
+ }
12
+ const defaultConnector = (p) => net.connect(p);
13
+ /**
14
+ * One NDJSON connection to a Herdr server socket (Unix socket or Windows named pipe).
15
+ *
16
+ * Events:
17
+ * - `event` (EventLine) pushed lines on a subscription connection
18
+ * - `error` (Error) a request-less error, e.g. `events_lost` on a subscription
19
+ * - `close` () the socket closed
20
+ */
21
+ export class HerdrConnection extends EventEmitter {
22
+ socket;
23
+ buf = '';
24
+ seq = 0;
25
+ pending = new Map();
26
+ closed = false;
27
+ constructor(socket) {
28
+ super();
29
+ this.socket = socket;
30
+ socket.setEncoding('utf8');
31
+ socket.on('data', (chunk) => this.onData(chunk));
32
+ socket.on('close', () => this.onClose());
33
+ socket.on('error', (err) => this.failAll(err));
34
+ }
35
+ static open(connectPath, connector = defaultConnector, timeoutMs = 5000) {
36
+ return new Promise((resolve, reject) => {
37
+ const socket = connector(connectPath);
38
+ const timer = setTimeout(() => {
39
+ socket.destroy();
40
+ reject(new HerdrError('connect_timeout', `no answer from ${connectPath}`));
41
+ }, timeoutMs);
42
+ socket.once('connect', () => {
43
+ clearTimeout(timer);
44
+ socket.removeListener('error', onErr);
45
+ resolve(new HerdrConnection(socket));
46
+ });
47
+ const onErr = (err) => {
48
+ clearTimeout(timer);
49
+ reject(err);
50
+ };
51
+ socket.once('error', onErr);
52
+ });
53
+ }
54
+ get isClosed() {
55
+ return this.closed;
56
+ }
57
+ request(method, params = {}, timeoutMs = 10_000) {
58
+ if (this.closed)
59
+ return Promise.reject(new HerdrError('closed', 'connection closed'));
60
+ const id = `bw_${++this.seq}`;
61
+ return new Promise((resolve, reject) => {
62
+ const p = { resolve, reject };
63
+ if (timeoutMs > 0) {
64
+ p.timer = setTimeout(() => {
65
+ this.pending.delete(id);
66
+ reject(new HerdrError('timeout', `${method} timed out`));
67
+ }, timeoutMs);
68
+ }
69
+ this.pending.set(id, p);
70
+ this.socket.write(JSON.stringify({ id, method, params }) + '\n');
71
+ });
72
+ }
73
+ /** Start a subscription on this connection. Resolves on `subscription_started`. */
74
+ async subscribe(subscriptions, timeoutMs = 10_000) {
75
+ const res = await this.request('events.subscribe', { subscriptions }, timeoutMs);
76
+ if (res.type !== 'subscription_started')
77
+ throw new HerdrError('unexpected', `subscribe answered ${res.type}`);
78
+ }
79
+ close() {
80
+ if (this.closed)
81
+ return;
82
+ this.socket.destroy();
83
+ }
84
+ onData(chunk) {
85
+ this.buf += chunk;
86
+ let nl;
87
+ while ((nl = this.buf.indexOf('\n')) >= 0) {
88
+ const raw = this.buf.slice(0, nl).trim();
89
+ this.buf = this.buf.slice(nl + 1);
90
+ if (!raw)
91
+ continue;
92
+ let line;
93
+ try {
94
+ line = JSON.parse(raw);
95
+ }
96
+ catch {
97
+ continue; // tolerate garbage lines
98
+ }
99
+ this.onLine(line);
100
+ }
101
+ }
102
+ onLine(line) {
103
+ if (isEvent(line)) {
104
+ this.emit('event', line);
105
+ return;
106
+ }
107
+ const p = this.pending.get(line.id);
108
+ if (p) {
109
+ this.pending.delete(line.id);
110
+ if (p.timer)
111
+ clearTimeout(p.timer);
112
+ if (isError(line))
113
+ p.reject(new HerdrError(line.error.code, line.error.message));
114
+ else
115
+ p.resolve(line.result);
116
+ return;
117
+ }
118
+ if (isError(line)) {
119
+ // e.g. events_lost, sent with the original subscription id after it started
120
+ this.emit('error', new HerdrError(line.error.code, line.error.message));
121
+ }
122
+ }
123
+ failAll(err) {
124
+ for (const [, p] of this.pending) {
125
+ if (p.timer)
126
+ clearTimeout(p.timer);
127
+ p.reject(err);
128
+ }
129
+ this.pending.clear();
130
+ }
131
+ onClose() {
132
+ this.closed = true;
133
+ this.failAll(new HerdrError('closed', 'connection closed'));
134
+ this.emit('close');
135
+ }
136
+ }
137
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/herdr/connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { HerdrConnection, HerdrError, type Connector } from './connection.js';
2
+ export * from './mapper.js';
3
+ export * from './paths.js';
4
+ export { HerdrSessionSource, HerdrSource, type LiveOptions, type SessionSourceOptions } from './source.js';
5
+ export type * from './protocol.js';
@@ -0,0 +1,5 @@
1
+ export { HerdrConnection, HerdrError } from './connection.js';
2
+ export * from './mapper.js';
3
+ export * from './paths.js';
4
+ export { HerdrSessionSource, HerdrSource } from './source.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/herdr/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAkB,MAAM,iBAAiB,CAAC;AAC9E,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAA+C,MAAM,aAAa,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { Delta, Member, Party, Status } from '../types.js';
2
+ import type { AgentInfo, AgentStatusChanged, PaneInfo, SessionSnapshot, WorkspaceInfo } from './protocol.js';
3
+ export declare function toStatus(s: unknown): Status;
4
+ /** Party ids are unique across sessions: `<session>/<workspace_id>`. */
5
+ export declare function partyId(session: string, workspaceId: string): string;
6
+ export interface MapContext {
7
+ session: string;
8
+ /** Branch names learned from worktree events, keyed by workspace_id. */
9
+ branches?: ReadonlyMap<string, string>;
10
+ }
11
+ export declare function memberFromPane(pane: PaneInfo | AgentInfo): Member | undefined;
12
+ export declare function partyFromWorkspace(ws: WorkspaceInfo, members: Record<string, Member>, ctx: MapContext): Party;
13
+ /** Build every party for one session from `session.snapshot`. Agent records win over pane records. */
14
+ export declare function partiesFromSnapshot(snap: SessionSnapshot, ctx: MapContext): Record<string, Party>;
15
+ /** Every pane id in the snapshot, for per-pane status subscriptions. */
16
+ export declare function paneIds(snap: SessionSnapshot): string[];
17
+ /**
18
+ * Apply a `pane.agent_status_changed` event. Returns the updated party, or
19
+ * undefined when the pane is not a known member (caller should re-read).
20
+ */
21
+ export declare function applyStatusChange(parties: Record<string, Party>, ev: AgentStatusChanged, ctx: MapContext): {
22
+ party: Party;
23
+ member: Member;
24
+ rollupChanged: boolean;
25
+ } | undefined;
26
+ /** Deltas that turn `prev` into `next`. New parties and header changes send the whole party. */
27
+ export declare function diffParties(prev: Record<string, Party>, next: Record<string, Party>, t: number): Delta[];
@@ -0,0 +1,141 @@
1
+ // Pure mapping from Herdr protocol records to the Bellwether world model.
2
+ import { resolveRole } from '../roles.js';
3
+ import { rollup } from '../rollup.js';
4
+ const STATUSES = new Set(['working', 'done', 'blocked', 'idle', 'unknown']);
5
+ export function toStatus(s) {
6
+ return typeof s === 'string' && STATUSES.has(s) ? s : 'unknown';
7
+ }
8
+ /** Party ids are unique across sessions: `<session>/<workspace_id>`. */
9
+ export function partyId(session, workspaceId) {
10
+ return `${session}/${workspaceId}`;
11
+ }
12
+ export function memberFromPane(pane) {
13
+ if (!pane.agent)
14
+ return undefined;
15
+ const tokens = pane.tokens ?? {};
16
+ const name = 'name' in pane ? pane.name : undefined;
17
+ const seq = 'state_change_seq' in pane ? pane.state_change_seq : undefined;
18
+ const m = {
19
+ paneId: pane.pane_id,
20
+ agent: pane.agent,
21
+ role: resolveRole({ tokens, agentName: name, title: pane.title }),
22
+ status: toStatus(pane.agent_status),
23
+ lastChange: seq ?? pane.revision ?? 0,
24
+ };
25
+ if (pane.title)
26
+ m.title = pane.title;
27
+ if (tokens.say)
28
+ m.say = tokens.say;
29
+ return m;
30
+ }
31
+ export function partyFromWorkspace(ws, members, ctx) {
32
+ const list = Object.values(members);
33
+ const p = {
34
+ id: partyId(ctx.session, ws.workspace_id),
35
+ label: ws.label,
36
+ session: ctx.session,
37
+ isWorktree: ws.worktree?.is_linked_worktree ?? false,
38
+ status: list.length ? rollup(list) : toStatus(ws.agent_status),
39
+ members,
40
+ tokens: { ...(ws.tokens ?? {}) },
41
+ };
42
+ if (ws.worktree?.repo_name)
43
+ p.repo = ws.worktree.repo_name;
44
+ const branch = ctx.branches?.get(ws.workspace_id);
45
+ if (branch)
46
+ p.branch = branch;
47
+ return p;
48
+ }
49
+ /** Build every party for one session from `session.snapshot`. Agent records win over pane records. */
50
+ export function partiesFromSnapshot(snap, ctx) {
51
+ const byWs = new Map();
52
+ const seen = new Set();
53
+ for (const rec of [...(snap.agents ?? []), ...(snap.panes ?? [])]) {
54
+ if (seen.has(rec.pane_id))
55
+ continue;
56
+ const m = memberFromPane(rec);
57
+ if (!m)
58
+ continue;
59
+ seen.add(rec.pane_id);
60
+ let ms = byWs.get(rec.workspace_id);
61
+ if (!ms)
62
+ byWs.set(rec.workspace_id, (ms = {}));
63
+ ms[m.paneId] = m;
64
+ }
65
+ const out = {};
66
+ for (const ws of snap.workspaces) {
67
+ // A workspace with no agents has nothing to show; it appears once an agent starts.
68
+ const members = byWs.get(ws.workspace_id);
69
+ if (!members)
70
+ continue;
71
+ const p = partyFromWorkspace(ws, members, ctx);
72
+ out[p.id] = p;
73
+ }
74
+ return out;
75
+ }
76
+ /** Every pane id in the snapshot, for per-pane status subscriptions. */
77
+ export function paneIds(snap) {
78
+ return [...new Set((snap.panes ?? []).map((p) => p.pane_id))].sort();
79
+ }
80
+ /**
81
+ * Apply a `pane.agent_status_changed` event. Returns the updated party, or
82
+ * undefined when the pane is not a known member (caller should re-read).
83
+ */
84
+ export function applyStatusChange(parties, ev, ctx) {
85
+ const party = parties[partyId(ctx.session, ev.workspace_id)];
86
+ const prev = party?.members[ev.pane_id];
87
+ if (!party || !prev)
88
+ return undefined;
89
+ const member = { ...prev, status: toStatus(ev.agent_status), lastChange: prev.lastChange + 1 };
90
+ if (ev.agent)
91
+ member.agent = ev.agent;
92
+ if (ev.title)
93
+ member.title = ev.title;
94
+ const members = { ...party.members, [member.paneId]: member };
95
+ const status = rollup(Object.values(members));
96
+ const next = { ...party, members, status };
97
+ return { party: next, member, rollupChanged: status !== party.status };
98
+ }
99
+ function sameMember(a, b) {
100
+ return a.agent === b.agent && a.role === b.role && a.status === b.status && a.title === b.title && a.say === b.say;
101
+ }
102
+ function samePartyHeader(a, b) {
103
+ return (a.label === b.label &&
104
+ a.repo === b.repo &&
105
+ a.branch === b.branch &&
106
+ a.isWorktree === b.isWorktree &&
107
+ a.status === b.status &&
108
+ a.session === b.session &&
109
+ JSON.stringify(a.tokens) === JSON.stringify(b.tokens));
110
+ }
111
+ /** Deltas that turn `prev` into `next`. New parties and header changes send the whole party. */
112
+ export function diffParties(prev, next, t) {
113
+ const out = [];
114
+ for (const id of Object.keys(prev))
115
+ if (!next[id])
116
+ out.push({ t, kind: 'removed', partyId: id });
117
+ for (const [id, np] of Object.entries(next)) {
118
+ const op = prev[id];
119
+ if (!op) {
120
+ out.push({ t, kind: 'party', party: np });
121
+ for (const m of Object.values(np.members))
122
+ if (m.say)
123
+ out.push({ t, kind: 'say', partyId: id, paneId: m.paneId, text: m.say });
124
+ continue;
125
+ }
126
+ for (const paneId of Object.keys(op.members))
127
+ if (!np.members[paneId])
128
+ out.push({ t, kind: 'removed', partyId: id, paneId });
129
+ for (const [paneId, nm] of Object.entries(np.members)) {
130
+ const om = op.members[paneId];
131
+ if (!om || !sameMember(om, nm))
132
+ out.push({ t, kind: 'member', partyId: id, member: nm });
133
+ if (nm.say && nm.say !== om?.say)
134
+ out.push({ t, kind: 'say', partyId: id, paneId, text: nm.say });
135
+ }
136
+ if (!samePartyHeader(op, np))
137
+ out.push({ t, kind: 'party', party: np });
138
+ }
139
+ return out;
140
+ }
141
+ //# sourceMappingURL=mapper.js.map