@legioncodeinc/honeycomb 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.
- package/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +15 -0
- package/LICENSE +661 -0
- package/README.md +268 -0
- package/assets/logos/fonts/Inter-Italic-VariableFont_opsz_wght.ttf +0 -0
- package/assets/logos/fonts/Inter-VariableFont_opsz_wght.ttf +0 -0
- package/assets/logos/fonts/JetBrainsMono-Bold.woff2 +0 -0
- package/assets/logos/fonts/JetBrainsMono-Medium.woff2 +0 -0
- package/assets/logos/fonts/JetBrainsMono-Regular.woff2 +0 -0
- package/assets/logos/fonts/JetBrainsMono-SemiBold.woff2 +0 -0
- package/assets/logos/honeycomb-memory-cluster.svg +17 -0
- package/assets/readme.md +117 -0
- package/assets/styles.css +11 -0
- package/assets/tokens/base.css +76 -0
- package/assets/tokens/colors.css +111 -0
- package/assets/tokens/fonts.css +32 -0
- package/assets/tokens/spacing.css +48 -0
- package/assets/tokens/typography.css +38 -0
- package/bundle/cli.js +20049 -0
- package/daemon/dashboard-app.js +118 -0
- package/daemon/index.js +49533 -0
- package/daemon/package.json +1 -0
- package/embeddings/embed-daemon.js +218 -0
- package/harnesses/claude-code/.claude-plugin/plugin.json +14 -0
- package/harnesses/claude-code/bundle/capture.js +16459 -0
- package/harnesses/claude-code/bundle/index.js +16459 -0
- package/harnesses/claude-code/bundle/package.json +1 -0
- package/harnesses/claude-code/bundle/pre-tool-use.js +16459 -0
- package/harnesses/claude-code/bundle/session-end.js +16459 -0
- package/harnesses/claude-code/bundle/session-start.js +16459 -0
- package/harnesses/claude-code/hooks/hooks.json +86 -0
- package/harnesses/codex/bundle/capture.js +16451 -0
- package/harnesses/codex/bundle/index.js +16451 -0
- package/harnesses/codex/bundle/package.json +1 -0
- package/harnesses/codex/bundle/pre-tool-use.js +16451 -0
- package/harnesses/codex/bundle/session-start.js +16451 -0
- package/harnesses/codex/package.json +7 -0
- package/harnesses/cursor/bundle/capture.js +16459 -0
- package/harnesses/cursor/bundle/index.js +16459 -0
- package/harnesses/cursor/bundle/package.json +1 -0
- package/harnesses/cursor/bundle/pre-tool-use.js +16459 -0
- package/harnesses/cursor/bundle/session-end.js +16459 -0
- package/harnesses/cursor/bundle/session-start.js +16459 -0
- package/harnesses/hermes/bundle/index.js +30 -0
- package/harnesses/hermes/bundle/package.json +1 -0
- package/harnesses/openclaw/dist/index.js +55 -0
- package/harnesses/openclaw/dist/package.json +1 -0
- package/harnesses/openclaw/openclaw.plugin.json +47 -0
- package/harnesses/openclaw/package.json +22 -0
- package/harnesses/pi/bundle/index.js +30 -0
- package/harnesses/pi/bundle/package.json +1 -0
- package/mcp/bundle/package.json +1 -0
- package/mcp/bundle/server.js +24014 -0
- package/package.json +137 -0
- package/scripts/ensure-embed-deps.mjs +67 -0
- package/scripts/ensure-tree-sitter.mjs +89 -0
- package/sdk/index.js +312 -0
- package/sdk/openai.js +63 -0
- package/sdk/package.json +1 -0
- package/sdk/react.js +40 -0
- package/sdk/vercel.js +43 -0
package/package.json
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@legioncodeinc/honeycomb",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"//go-public": "Go-public switches are flipped: scoped name, public+provenance publishConfig live, `private` removed. CI auth is npm Trusted Publishing (OIDC); there is NO NPM_TOKEN. The go-live procedure is RELEASING.md 'Cut the release': the first publish is a one-time manual 2FA bootstrap that creates the package, after which every CI publish from release.yaml is tokenless OIDC.",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public",
|
|
7
|
+
"provenance": true
|
|
8
|
+
},
|
|
9
|
+
"description": "Honeycomb monorepo foundation: a long-lived daemon plus thin clients for six coding harnesses, the unified honeycomb CLI, the MCP server, and the embed daemon.",
|
|
10
|
+
"license": "AGPL-3.0-or-later",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"//build-order": "Fixed dependency direction enforced by import direction under one tsc pass: (1) core = src/shared + src/daemon-client, (2) connector-base = src/daemon, (3) plugins/native = embeddings, (4) connectors = harnesses/* + mcp + src/cli, (5) assembled distribution = esbuild per-target bundles (PRD-001b). tsc compiles the whole graph in one pass; dependents never import upward, so the single tsc invocation respects this order. PRD-001b appends '&& node esbuild.config.mjs' to the build script; that seam is intentional.",
|
|
13
|
+
"bin": {
|
|
14
|
+
"honeycomb": "bundle/cli.js"
|
|
15
|
+
},
|
|
16
|
+
"//exports": "PRD-019e: @legioncodeinc/honeycomb subpath exports. The core entry (.) is the fetch-only, browser-safe HoneycombClient (`@legioncodeinc/honeycomb`); the three framework helpers ship as separate entry points (`@legioncodeinc/honeycomb/react`, `/vercel`, `/openai`) reusing the core's token/actor model. react + ai are peerDependencies (never bundled into core).",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": "./sdk/index.js",
|
|
19
|
+
"./react": "./sdk/react.js",
|
|
20
|
+
"./vercel": "./sdk/vercel.js",
|
|
21
|
+
"./openai": "./sdk/openai.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bundle",
|
|
25
|
+
"sdk",
|
|
26
|
+
"daemon",
|
|
27
|
+
"assets/styles.css",
|
|
28
|
+
"assets/tokens",
|
|
29
|
+
"assets/logos/honeycomb-memory-cluster.svg",
|
|
30
|
+
"assets/logos/fonts",
|
|
31
|
+
"harnesses/claude-code/bundle",
|
|
32
|
+
"harnesses/claude-code/.claude-plugin",
|
|
33
|
+
"harnesses/claude-code/hooks",
|
|
34
|
+
"harnesses/codex/bundle",
|
|
35
|
+
"harnesses/codex/package.json",
|
|
36
|
+
"harnesses/cursor/bundle",
|
|
37
|
+
"harnesses/hermes/bundle",
|
|
38
|
+
"harnesses/pi/bundle",
|
|
39
|
+
"harnesses/openclaw/dist",
|
|
40
|
+
"harnesses/openclaw/openclaw.plugin.json",
|
|
41
|
+
"harnesses/openclaw/package.json",
|
|
42
|
+
"mcp/bundle",
|
|
43
|
+
"embeddings/embed-daemon.js",
|
|
44
|
+
".claude-plugin",
|
|
45
|
+
"scripts/ensure-tree-sitter.mjs",
|
|
46
|
+
"scripts/ensure-embed-deps.mjs",
|
|
47
|
+
"README.md"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"prebuild": "node scripts/sync-versions.mjs",
|
|
51
|
+
"version": "node scripts/sync-versions.mjs && git add .claude-plugin/plugin.json harnesses/claude-code/.claude-plugin/plugin.json harnesses/openclaw/openclaw.plugin.json harnesses/openclaw/package.json harnesses/codex/package.json .claude-plugin/marketplace.json",
|
|
52
|
+
"build": "tsc && node esbuild.config.mjs",
|
|
53
|
+
"bundle": "node esbuild.config.mjs",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"lint": "biome check .",
|
|
56
|
+
"format": "biome format --write .",
|
|
57
|
+
"dup": "jscpd src harnesses mcp embeddings",
|
|
58
|
+
"test": "vitest run",
|
|
59
|
+
"test:watch": "vitest",
|
|
60
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
61
|
+
"smoke:golden-path": "node scripts/golden-path-smoke.mjs",
|
|
62
|
+
"smoke:login": "node scripts/login-smoke.mjs",
|
|
63
|
+
"smoke:data-api": "node scripts/dogfood-acceptance-smoke.mjs",
|
|
64
|
+
"eval:recall": "node scripts/eval-recall.mjs",
|
|
65
|
+
"eval:prime": "node scripts/eval-prime.mjs",
|
|
66
|
+
"bench:hybrid": "node scripts/bench-hybrid.mjs",
|
|
67
|
+
"deeplake:stress": "node scripts/deeplake-stress.mjs",
|
|
68
|
+
"audit:openclaw": "node scripts/audit-openclaw-bundle.mjs",
|
|
69
|
+
"audit:sql": "node scripts/audit-sql-safety.mjs",
|
|
70
|
+
"mutation": "npm run mutation:sql && npm run mutation:prune && npm run mutation:normalize && npm run mutation:state",
|
|
71
|
+
"mutation:sql": "stryker run stryker/sql.json",
|
|
72
|
+
"mutation:prune": "stryker run stryker/prune.json",
|
|
73
|
+
"mutation:normalize": "stryker run stryker/normalize.json",
|
|
74
|
+
"mutation:state": "stryker run stryker/state.json",
|
|
75
|
+
"pack:check": "node scripts/pack-check.mjs",
|
|
76
|
+
"rebuild:native": "node scripts/ensure-tree-sitter.mjs",
|
|
77
|
+
"ensure:embed-deps": "node scripts/ensure-embed-deps.mjs",
|
|
78
|
+
"ci": "npm run typecheck && npm run dup && npm run test && npm run audit:sql",
|
|
79
|
+
"postinstall": "node scripts/ensure-tree-sitter.mjs && node scripts/ensure-embed-deps.mjs",
|
|
80
|
+
"prepack": "npm run build",
|
|
81
|
+
"smoke:daemon-bundle": "node scripts/smoke-daemon-bundle.mjs"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@biomejs/biome": "^2.5.0",
|
|
85
|
+
"@stryker-mutator/core": "^8.7.1",
|
|
86
|
+
"@stryker-mutator/vitest-runner": "^8.7.1",
|
|
87
|
+
"@types/node": "^22.0.0",
|
|
88
|
+
"@types/react": "^18.3.31",
|
|
89
|
+
"@types/react-dom": "^18.3.7",
|
|
90
|
+
"@vitest/coverage-v8": "^3.2.6",
|
|
91
|
+
"esbuild": "^0.28.1",
|
|
92
|
+
"fast-check": "^4.8.0",
|
|
93
|
+
"jscpd": "^4.0.5",
|
|
94
|
+
"jsdom": "^25.0.1",
|
|
95
|
+
"react": "18.3.1",
|
|
96
|
+
"react-dom": "18.3.1",
|
|
97
|
+
"typescript": "^5.7.0",
|
|
98
|
+
"vitest": "^3.2.6"
|
|
99
|
+
},
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=22.5.0"
|
|
102
|
+
},
|
|
103
|
+
"//peerDependencies": "PRD-019e: react powers @legioncodeinc/honeycomb/react; ai powers @legioncodeinc/honeycomb/vercel. Both are OPTIONAL peers (peerDependenciesMeta) so the core entry stays dependency-free for Node/Bun/browser. The core client (.) pulls in NEITHER.",
|
|
104
|
+
"peerDependencies": {
|
|
105
|
+
"ai": ">=3.0.0",
|
|
106
|
+
"react": ">=18.0.0"
|
|
107
|
+
},
|
|
108
|
+
"peerDependenciesMeta": {
|
|
109
|
+
"react": {
|
|
110
|
+
"optional": true
|
|
111
|
+
},
|
|
112
|
+
"ai": {
|
|
113
|
+
"optional": true
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"dependencies": {
|
|
117
|
+
"@hono/node-server": "^1.19.14",
|
|
118
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
119
|
+
"@noble/ciphers": "^2.2.0",
|
|
120
|
+
"hono": "^4.12.25",
|
|
121
|
+
"tree-sitter-wasms": "^0.1.13",
|
|
122
|
+
"web-tree-sitter": "^0.22.6",
|
|
123
|
+
"yaml": "^2.9.0",
|
|
124
|
+
"zod": "^4.4.3"
|
|
125
|
+
},
|
|
126
|
+
"//optionalDependencies": "PRD-025 D-2: the embedding RUNTIME (@huggingface/transformers + its ONNX native runtime, ~600 MB with the nomic-embed-text-v1.5 model acquired at first-run) ships as an OPTIONAL dependency, NOT in the `files` allowlist. This keeps the published @legioncodeinc/honeycomb tarball LEAN (the model is downloaded + cached on the daemon's first warmup, not packed — AC-7) and keeps `npm i` fast for everyone; a `--no-optional` / slimmed / offline install simply runs recall on the BM25/ILIKE lexical fallback (no quality cliff — D-4). The embed daemon dynamic-imports this only at warmup, so the bundle + CI never require it.",
|
|
127
|
+
"optionalDependencies": {
|
|
128
|
+
"@huggingface/transformers": "^3.8.1"
|
|
129
|
+
},
|
|
130
|
+
"//overrides": "Dependabot transitive-devDependency remediation. All are DEV-only and never ship (the `files` allowlist packs built bundles, not node_modules), so consumer risk is nil — these clear the dev/CI tree. tmp ^0.2.6 fixes GHSA-ph9p-34f9-6g65 (HIGH path traversal) + GHSA-52f5-9888-hmc6 (symlink write), reached only via @stryker-mutator/core -> @inquirer/prompts -> external-editor -> tmp (which calls only tmpNameSync, stable across the 0.0.33->0.2.x major). esbuild ^0.28.1 fixes GHSA-g7r4-m6w7-qqqr (Windows dev-server file read) in vitest's nested copy; the direct dep is already 0.28.1. @babel/core ^7.29.6 fixes GHSA-4x5r-pxfx-6jf8 (sourceMappingURL file read) under @stryker-mutator/instrumenter. ajv ^8.20.0 fixes GHSA-2g4f-4pwh-qvx6 ($data ReDoS) under @stryker-mutator/core's schema validator — a same-major bump (8.17.1 -> 8.20.x), preferred over npm audit's suggested breaking @stryker-mutator/core 9.x major. Validated by npm run mutation (exercises tmp+babel+ajv schema load) + npm run ci/build (exercises esbuild).",
|
|
131
|
+
"overrides": {
|
|
132
|
+
"tmp": "^0.2.6",
|
|
133
|
+
"esbuild": "^0.28.1",
|
|
134
|
+
"@babel/core": "^7.29.6",
|
|
135
|
+
"ajv": "^8.20.0"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// PRD-025 Wave 2 (D-2 / D-3 / AC-1 / AC-7) — first-run embedding-deps heal.
|
|
3
|
+
//
|
|
4
|
+
// Mirrors scripts/ensure-tree-sitter.mjs: a fast, NON-FATAL sanity check run from
|
|
5
|
+
// the `postinstall` hook. It HEALS NOTHING heavy and DOWNLOADS NOTHING here — the
|
|
6
|
+
// ~600 MB model is acquired LATER, lazily, on the daemon's first warmup (D-2: the
|
|
7
|
+
// model is acquired at first run, NEVER packed into the npm tarball; D-3: the
|
|
8
|
+
// download is background-warm and never blocks login or the first recall). This
|
|
9
|
+
// script only REPORTS whether the optional inference stack
|
|
10
|
+
// (`@huggingface/transformers`) resolved, so a consumer sees one clear line at
|
|
11
|
+
// install time instead of an opaque failure when the daemon later tries to warm.
|
|
12
|
+
//
|
|
13
|
+
// Why it stays in the `files` allowlist + `postinstall`: parity with
|
|
14
|
+
// ensure-tree-sitter (the install hook references it by path), and a deterministic,
|
|
15
|
+
// non-fatal install experience. It ALWAYS exits 0 (unless strict CI mode) — an
|
|
16
|
+
// end-user `npm i` must NEVER hard-break because the optional embed stack is absent;
|
|
17
|
+
// embeddings simply stay OFF until the deps are present (the BM25 lexical fallback
|
|
18
|
+
// has no quality cliff — PRD-025 D-4).
|
|
19
|
+
|
|
20
|
+
import { createRequire } from "node:module";
|
|
21
|
+
|
|
22
|
+
const ROOT = process.cwd();
|
|
23
|
+
const require = createRequire(`${ROOT}/`);
|
|
24
|
+
|
|
25
|
+
// Recursion guard for nested npm calls (parity with ensure-tree-sitter).
|
|
26
|
+
if (process.env.ENSURE_EMBED_RUNNING) process.exit(0);
|
|
27
|
+
|
|
28
|
+
// The opt-OUT (PRD-025 D-1): an explicit `HONEYCOMB_EMBEDDINGS=false`/`0` means the
|
|
29
|
+
// user does not want embeddings — say so and exit cleanly, never probing.
|
|
30
|
+
const raw = (process.env.HONEYCOMB_EMBEDDINGS ?? "").trim().toLowerCase();
|
|
31
|
+
if (raw === "false" || raw === "0") {
|
|
32
|
+
console.error(
|
|
33
|
+
"[ensure-embed-deps] HONEYCOMB_EMBEDDINGS opt-out set — embeddings disabled, recall is lexical-only. Skipping.",
|
|
34
|
+
);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// The optional inference stack. It is an `optionalDependency` (~600 MB with its
|
|
39
|
+
// native ONNX runtime), so a slimmed / offline / `--no-optional` install legitimately
|
|
40
|
+
// lacks it. Resolve-only: we do NOT import it (importing would load native bindings
|
|
41
|
+
// at install time — exactly what we avoid; the daemon loads it lazily on warmup).
|
|
42
|
+
let present = true;
|
|
43
|
+
try {
|
|
44
|
+
require.resolve("@huggingface/transformers");
|
|
45
|
+
} catch {
|
|
46
|
+
present = false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (present) {
|
|
50
|
+
console.error(
|
|
51
|
+
"[ensure-embed-deps] OK — @huggingface/transformers present. The nomic-embed-text-v1.5 model " +
|
|
52
|
+
"(~600 MB) downloads + caches on first daemon warmup (one time), then reuses the cached dir.",
|
|
53
|
+
);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Absent: this is the COMMON, non-error case for a lean install. Embeddings stay OFF
|
|
58
|
+
// and recall is the BM25/ILIKE lexical fallback (no quality cliff — D-4). In strict CI
|
|
59
|
+
// mode a missing optional stack can be made a hard signal; otherwise it is informational.
|
|
60
|
+
const strict = process.env.HONEYCOMB_STRICT_POSTINSTALL === "1";
|
|
61
|
+
console.error(
|
|
62
|
+
"[ensure-embed-deps] @huggingface/transformers not installed — semantic recall is OFF; recall " +
|
|
63
|
+
"falls back to lexical (BM25/ILIKE), which is fine. To enable semantic recall, install the " +
|
|
64
|
+
"optional embedding deps (`npm i @huggingface/transformers`) and restart the daemon." +
|
|
65
|
+
(strict ? " (strict mode — failing this install)" : " (non-fatal)"),
|
|
66
|
+
);
|
|
67
|
+
process.exit(strict ? 1 : 0);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Confirms the tree-sitter WASM parser stack is present and loadable after install
|
|
3
|
+
// (PRD-014 codebase graph, D-1). This script HEALS NOTHING and COMPILES NOTHING:
|
|
4
|
+
// the parser is `web-tree-sitter` (a WASM/emscripten runtime) + `tree-sitter-wasms`
|
|
5
|
+
// (prebuilt `.wasm` grammars), so there is no native binding to build, no node-gyp,
|
|
6
|
+
// no C/C++ toolchain, and no per-platform/per-ABI compile. That is the whole point
|
|
7
|
+
// of choosing WASM over native `tree-sitter` + `tree-sitter-<lang>`: the install is
|
|
8
|
+
// deterministic and identical across the CI matrix (ubuntu Node 22/24 + windows-smoke),
|
|
9
|
+
// with no postinstall compile that could break Windows or linux-arm64.
|
|
10
|
+
//
|
|
11
|
+
// Why this file still exists (and stays in the `files` allowlist + `postinstall`):
|
|
12
|
+
// 1. Backwards-compatible name — the build script + CI reference `rebuild:native`
|
|
13
|
+
// and `postinstall` by this path; keeping it avoids churn in those surfaces.
|
|
14
|
+
// 2. A fast, non-fatal SANITY check: if a consumer's install dropped a grammar
|
|
15
|
+
// `.wasm` (a partial extract, a pruned `node_modules`), we say so clearly
|
|
16
|
+
// rather than letting the daemon fail later with an opaque WASM load error.
|
|
17
|
+
//
|
|
18
|
+
// It ALWAYS exits 0 (unless explicitly run in strict CI mode and a grammar is
|
|
19
|
+
// genuinely missing): an end-user consumer must never get a hard install break from
|
|
20
|
+
// this hook.
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { createRequire } from "node:module";
|
|
23
|
+
|
|
24
|
+
const ROOT = process.cwd();
|
|
25
|
+
const require = createRequire(`${ROOT}/`);
|
|
26
|
+
|
|
27
|
+
// Recursion guard for nested npm calls (kept for parity with prior behaviour).
|
|
28
|
+
if (process.env.ENSURE_TS_RUNNING) process.exit(0);
|
|
29
|
+
|
|
30
|
+
// The nine PRD-014 languages map to these grammar `.wasm` files (TS routes both
|
|
31
|
+
// `tree-sitter-typescript` and `tree-sitter-tsx`). Located by resolving the
|
|
32
|
+
// `tree-sitter-wasms` package and reading its `out/` directory — the SAME anchor
|
|
33
|
+
// the runtime extractor uses (`src/daemon/runtime/codebase/extract.ts`).
|
|
34
|
+
const GRAMMARS = [
|
|
35
|
+
"tree-sitter-typescript",
|
|
36
|
+
"tree-sitter-tsx",
|
|
37
|
+
"tree-sitter-javascript",
|
|
38
|
+
"tree-sitter-python",
|
|
39
|
+
"tree-sitter-go",
|
|
40
|
+
"tree-sitter-rust",
|
|
41
|
+
"tree-sitter-java",
|
|
42
|
+
"tree-sitter-ruby",
|
|
43
|
+
"tree-sitter-c",
|
|
44
|
+
"tree-sitter-cpp",
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Greenfield / not-yet-installed short-circuit: if the parser deps are not present
|
|
48
|
+
// (a checkout before `npm install`, or a slimmed environment), there is nothing to
|
|
49
|
+
// check. Log and exit 0 so `npm install` / `npm run rebuild:native` never breaks.
|
|
50
|
+
let wasmDir;
|
|
51
|
+
try {
|
|
52
|
+
wasmDir = require.resolve("tree-sitter-wasms/package.json").replace(/package\.json$/, "out/");
|
|
53
|
+
} catch {
|
|
54
|
+
console.error(
|
|
55
|
+
"[ensure-tree-sitter] web-tree-sitter / tree-sitter-wasms not installed yet — nothing to check. Skipping.",
|
|
56
|
+
);
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Confirm the web-tree-sitter runtime resolves too (it carries its own
|
|
61
|
+
// `tree-sitter.wasm` emscripten runtime loaded at parse time).
|
|
62
|
+
let runtimeOk = true;
|
|
63
|
+
try {
|
|
64
|
+
require.resolve("web-tree-sitter");
|
|
65
|
+
} catch {
|
|
66
|
+
runtimeOk = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const missing = GRAMMARS.filter((g) => !existsSync(`${wasmDir}${g}.wasm`));
|
|
70
|
+
|
|
71
|
+
if (runtimeOk && missing.length === 0) {
|
|
72
|
+
console.error(
|
|
73
|
+
`[ensure-tree-sitter] OK — web-tree-sitter runtime + ${GRAMMARS.length} WASM grammars present (no native build needed).`,
|
|
74
|
+
);
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Something is missing. In strict CI mode (HONEYCOMB_STRICT_POSTINSTALL=1) this is a
|
|
79
|
+
// hard failure so a partial install surfaces as a red check; otherwise it is a
|
|
80
|
+
// non-fatal warning so an end-user install never breaks.
|
|
81
|
+
const strict = process.env.HONEYCOMB_STRICT_POSTINSTALL === "1";
|
|
82
|
+
console.error(
|
|
83
|
+
"[ensure-tree-sitter] WARNING: tree-sitter WASM stack incomplete — " +
|
|
84
|
+
(runtimeOk ? "" : "web-tree-sitter runtime not resolvable; ") +
|
|
85
|
+
(missing.length ? `missing grammars: ${missing.join(", ")}. ` : "") +
|
|
86
|
+
"Re-run `npm install` to restore the parser deps." +
|
|
87
|
+
(strict ? " (strict mode — failing this install)" : " (non-fatal)"),
|
|
88
|
+
);
|
|
89
|
+
process.exit(strict ? 1 : 0);
|
package/sdk/index.js
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
// dist/src/sdk/contracts.js
|
|
2
|
+
function notImplemented(what) {
|
|
3
|
+
throw new Error(`PRD-019e: not implemented \u2014 ${what}`);
|
|
4
|
+
}
|
|
5
|
+
var HoneycombError = class extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = new.target.name;
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
var ApiError = class extends HoneycombError {
|
|
12
|
+
status;
|
|
13
|
+
body;
|
|
14
|
+
constructor(message, status, body) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.status = status;
|
|
17
|
+
this.body = body;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var NetworkError = class extends HoneycombError {
|
|
21
|
+
cause;
|
|
22
|
+
constructor(message, cause) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.cause = cause;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var TimeoutError = class extends HoneycombError {
|
|
28
|
+
timeoutMs;
|
|
29
|
+
constructor(message, timeoutMs) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.timeoutMs = timeoutMs;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
function defaultRetryPolicy() {
|
|
35
|
+
return {
|
|
36
|
+
maxAttempts(method) {
|
|
37
|
+
return method === "GET" ? 3 : 1;
|
|
38
|
+
},
|
|
39
|
+
backoffMs(attempt) {
|
|
40
|
+
return attempt * 100;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// dist/src/sdk/client.js
|
|
46
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
47
|
+
var SECRET_REDACTED = "[REDACTED]";
|
|
48
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
49
|
+
function isTokenTransportSafe(baseUrl) {
|
|
50
|
+
let parsed;
|
|
51
|
+
try {
|
|
52
|
+
parsed = new URL(baseUrl);
|
|
53
|
+
} catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (parsed.protocol === "https:")
|
|
57
|
+
return true;
|
|
58
|
+
if (parsed.protocol === "http:")
|
|
59
|
+
return LOOPBACK_HOSTS.has(parsed.hostname);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
var HEADER_ACTOR = "x-honeycomb-actor";
|
|
63
|
+
var HEADER_ACTOR_TYPE = "x-honeycomb-actor-type";
|
|
64
|
+
var HEADER_RUNTIME_PATH = "x-honeycomb-runtime-path";
|
|
65
|
+
var HEADER_SESSION = "x-honeycomb-session";
|
|
66
|
+
var SESSION_GROUP_PREFIXES = ["/api/memories", "/memory"];
|
|
67
|
+
function isSdkSessionGroupPath(path) {
|
|
68
|
+
return SESSION_GROUP_PREFIXES.some((p) => path === p || path.startsWith(`${p}/`) || path.startsWith(`${p}?`));
|
|
69
|
+
}
|
|
70
|
+
function createHoneycombClient(opts) {
|
|
71
|
+
const fetchImpl = opts.fetch ?? ((input, init) => fetch(input, init));
|
|
72
|
+
const retry = opts.retry ?? defaultRetryPolicy();
|
|
73
|
+
const clientTimeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
74
|
+
const baseUrl = opts.daemonUrl.replace(/\/+$/, "");
|
|
75
|
+
const tokenTransportSafe = isTokenTransportSafe(baseUrl);
|
|
76
|
+
let sdkSessionCounter = 0;
|
|
77
|
+
function mintSdkSessionId() {
|
|
78
|
+
sdkSessionCounter += 1;
|
|
79
|
+
return `sdk-${opts.actor}-${sdkSessionCounter}`;
|
|
80
|
+
}
|
|
81
|
+
function buildHeaders(hasBody, path) {
|
|
82
|
+
const headers = {
|
|
83
|
+
[HEADER_ACTOR]: opts.actor,
|
|
84
|
+
[HEADER_ACTOR_TYPE]: opts.actorType,
|
|
85
|
+
// The SDK is a plugin-path thin client; the daemon enforces, we stamp (D-6).
|
|
86
|
+
[HEADER_RUNTIME_PATH]: "plugin"
|
|
87
|
+
};
|
|
88
|
+
if (isSdkSessionGroupPath(path))
|
|
89
|
+
headers[HEADER_SESSION] = mintSdkSessionId();
|
|
90
|
+
if (hasBody)
|
|
91
|
+
headers["content-type"] = "application/json";
|
|
92
|
+
if (opts.token !== void 0 && opts.token.length > 0 && tokenTransportSafe) {
|
|
93
|
+
headers.authorization = `Bearer ${opts.token}`;
|
|
94
|
+
}
|
|
95
|
+
return headers;
|
|
96
|
+
}
|
|
97
|
+
async function dispatchOnce(req, budgetMs) {
|
|
98
|
+
const controller = new AbortController();
|
|
99
|
+
let timedOut = false;
|
|
100
|
+
const timer = setTimeout(() => {
|
|
101
|
+
timedOut = true;
|
|
102
|
+
controller.abort();
|
|
103
|
+
}, budgetMs);
|
|
104
|
+
try {
|
|
105
|
+
const init = {
|
|
106
|
+
method: req.method,
|
|
107
|
+
headers: buildHeaders(req.body !== void 0, req.path),
|
|
108
|
+
signal: controller.signal
|
|
109
|
+
};
|
|
110
|
+
if (req.body !== void 0)
|
|
111
|
+
init.body = JSON.stringify(req.body);
|
|
112
|
+
return await fetchImpl(`${baseUrl}${req.path}`, init);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
if (timedOut) {
|
|
115
|
+
throw new TimeoutError(`request to ${req.path} exceeded ${budgetMs}ms`, budgetMs);
|
|
116
|
+
}
|
|
117
|
+
throw new NetworkError(`transport failure calling ${req.path}`, err);
|
|
118
|
+
} finally {
|
|
119
|
+
clearTimeout(timer);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function isTransientStatus(status) {
|
|
123
|
+
return status === 429 || status >= 500 && status <= 599;
|
|
124
|
+
}
|
|
125
|
+
function sleep(ms) {
|
|
126
|
+
if (ms <= 0)
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
129
|
+
}
|
|
130
|
+
async function request(req) {
|
|
131
|
+
const budgetMs = req.timeoutMs ?? clientTimeoutMs;
|
|
132
|
+
const maxAttempts = retry.maxAttempts(req.method);
|
|
133
|
+
let lastError;
|
|
134
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
135
|
+
let res;
|
|
136
|
+
try {
|
|
137
|
+
res = await dispatchOnce(req, budgetMs);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
lastError = err;
|
|
140
|
+
if (err instanceof TimeoutError)
|
|
141
|
+
throw err;
|
|
142
|
+
if (attempt < maxAttempts) {
|
|
143
|
+
await sleep(retry.backoffMs(attempt));
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
throw err;
|
|
147
|
+
}
|
|
148
|
+
if (res.ok)
|
|
149
|
+
return await parseBody(res);
|
|
150
|
+
if (isTransientStatus(res.status) && attempt < maxAttempts) {
|
|
151
|
+
lastError = new ApiError(`daemon returned ${res.status} for ${req.path}`, res.status, await safeBody(res));
|
|
152
|
+
await sleep(retry.backoffMs(attempt));
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
throw new ApiError(`daemon returned ${res.status} for ${req.path}`, res.status, await safeBody(res));
|
|
156
|
+
}
|
|
157
|
+
if (lastError !== void 0)
|
|
158
|
+
throw lastError;
|
|
159
|
+
throw new NetworkError(`request to ${req.path} failed after ${maxAttempts} attempts`);
|
|
160
|
+
}
|
|
161
|
+
async function parseBody(res) {
|
|
162
|
+
const text = await res.text();
|
|
163
|
+
if (text.length === 0)
|
|
164
|
+
return void 0;
|
|
165
|
+
try {
|
|
166
|
+
return JSON.parse(text);
|
|
167
|
+
} catch {
|
|
168
|
+
return text;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function safeBody(res) {
|
|
172
|
+
try {
|
|
173
|
+
return await parseBody(res);
|
|
174
|
+
} catch {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const memory = {
|
|
179
|
+
async search(query, o) {
|
|
180
|
+
const body = await request({
|
|
181
|
+
method: "POST",
|
|
182
|
+
path: "/api/memories/recall",
|
|
183
|
+
body: o?.limit !== void 0 ? { query, limit: o.limit } : { query }
|
|
184
|
+
});
|
|
185
|
+
if (body?.results !== void 0)
|
|
186
|
+
return body.results;
|
|
187
|
+
return (body?.hits ?? []).map((h) => ({
|
|
188
|
+
path: h.id ?? "",
|
|
189
|
+
text: h.text ?? "",
|
|
190
|
+
...h.score !== void 0 ? { score: h.score } : {}
|
|
191
|
+
}));
|
|
192
|
+
},
|
|
193
|
+
async store(text, o) {
|
|
194
|
+
await request({
|
|
195
|
+
method: "POST",
|
|
196
|
+
path: "/api/memories",
|
|
197
|
+
body: o?.path !== void 0 ? { content: text, normalizedContent: o.path } : { content: text }
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
async get(path) {
|
|
201
|
+
return await request({
|
|
202
|
+
method: "GET",
|
|
203
|
+
path: `/api/memories/${encodeURIComponent(path)}`
|
|
204
|
+
});
|
|
205
|
+
},
|
|
206
|
+
async list(prefix) {
|
|
207
|
+
const qs = prefix !== void 0 ? `?prefix=${encodeURIComponent(prefix)}` : "";
|
|
208
|
+
const body = await request({
|
|
209
|
+
method: "GET",
|
|
210
|
+
path: `/api/memories${qs}`
|
|
211
|
+
});
|
|
212
|
+
return body?.results ?? [];
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
const hooks = {
|
|
216
|
+
async call(endpoint, body) {
|
|
217
|
+
return await request({ method: "POST", path: `/api/hooks/${endpoint}`, body });
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
const connectors = {
|
|
221
|
+
async list() {
|
|
222
|
+
return await listOf("/api/connectors");
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
const documents = {
|
|
226
|
+
async list() {
|
|
227
|
+
return await listOf("/api/documents");
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
const sources = {
|
|
231
|
+
async list() {
|
|
232
|
+
return await listOf("/api/sources");
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
const skills = {
|
|
236
|
+
async list() {
|
|
237
|
+
return await listOf("/api/skills");
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const goals = {
|
|
241
|
+
async list() {
|
|
242
|
+
return await listOf("/api/goals");
|
|
243
|
+
},
|
|
244
|
+
async add(goal) {
|
|
245
|
+
await request({ method: "POST", path: "/api/goals", body: { goal } });
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const health = {
|
|
249
|
+
async check() {
|
|
250
|
+
const body = await request({ method: "GET", path: "/health" });
|
|
251
|
+
return { ok: body?.ok === true || body?.status === "ok" };
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
async function listOf(path) {
|
|
255
|
+
const body = await request({ method: "GET", path });
|
|
256
|
+
if (Array.isArray(body))
|
|
257
|
+
return body;
|
|
258
|
+
if (body !== null && typeof body === "object") {
|
|
259
|
+
const values = Object.values(body);
|
|
260
|
+
const arr = values.find((v) => Array.isArray(v));
|
|
261
|
+
if (Array.isArray(arr))
|
|
262
|
+
return arr;
|
|
263
|
+
}
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
const secrets = {
|
|
267
|
+
async list(prefix) {
|
|
268
|
+
const body = await request({ method: "GET", path: "/api/secrets" });
|
|
269
|
+
const names = body?.names ?? [];
|
|
270
|
+
const filtered = prefix !== void 0 ? names.filter((n) => n.startsWith(prefix)) : names;
|
|
271
|
+
return filtered.map((name) => ({ name }));
|
|
272
|
+
},
|
|
273
|
+
async exec(command) {
|
|
274
|
+
const body = await request({
|
|
275
|
+
method: "POST",
|
|
276
|
+
path: "/api/secrets/exec",
|
|
277
|
+
body: { command }
|
|
278
|
+
});
|
|
279
|
+
const redactedOutput = typeof body?.redactedOutput === "string" ? body.redactedOutput : SECRET_REDACTED;
|
|
280
|
+
return { redactedOutput };
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
return {
|
|
284
|
+
async remember(text, o) {
|
|
285
|
+
await memory.store(text, o);
|
|
286
|
+
},
|
|
287
|
+
async recall(query, o) {
|
|
288
|
+
return await memory.search(query, o);
|
|
289
|
+
},
|
|
290
|
+
memory,
|
|
291
|
+
hooks,
|
|
292
|
+
connectors,
|
|
293
|
+
documents,
|
|
294
|
+
sources,
|
|
295
|
+
skills,
|
|
296
|
+
goals,
|
|
297
|
+
health,
|
|
298
|
+
secrets
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
export {
|
|
302
|
+
ApiError,
|
|
303
|
+
DEFAULT_TIMEOUT_MS,
|
|
304
|
+
HoneycombError,
|
|
305
|
+
NetworkError,
|
|
306
|
+
SECRET_REDACTED,
|
|
307
|
+
TimeoutError,
|
|
308
|
+
createHoneycombClient,
|
|
309
|
+
defaultRetryPolicy,
|
|
310
|
+
isTokenTransportSafe,
|
|
311
|
+
notImplemented
|
|
312
|
+
};
|
package/sdk/openai.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// dist/src/sdk/openai.js
|
|
2
|
+
var OPENAI_TOOL_RECALL = "honeycomb_recall";
|
|
3
|
+
var OPENAI_TOOL_REMEMBER = "honeycomb_remember";
|
|
4
|
+
function createOpenAiTools() {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: OPENAI_TOOL_RECALL,
|
|
10
|
+
description: "Recall relevant memories from Honeycomb for a query.",
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
query: { type: "string", description: "The text to recall memories for." },
|
|
15
|
+
limit: { type: "number", description: "Max results to return." }
|
|
16
|
+
},
|
|
17
|
+
required: ["query"],
|
|
18
|
+
additionalProperties: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: "function",
|
|
24
|
+
function: {
|
|
25
|
+
name: OPENAI_TOOL_REMEMBER,
|
|
26
|
+
description: "Store a memory in Honeycomb.",
|
|
27
|
+
parameters: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
text: { type: "string", description: "The memory text to store." },
|
|
31
|
+
path: { type: "string", description: "Optional memory path to store under." }
|
|
32
|
+
},
|
|
33
|
+
required: ["text"],
|
|
34
|
+
additionalProperties: false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
async function dispatchOpenAiToolCall(client, name, args) {
|
|
41
|
+
const a = args !== null && typeof args === "object" ? args : {};
|
|
42
|
+
switch (name) {
|
|
43
|
+
case OPENAI_TOOL_RECALL: {
|
|
44
|
+
const query = String(a.query ?? "");
|
|
45
|
+
const limit = typeof a.limit === "number" ? a.limit : void 0;
|
|
46
|
+
return await client.recall(query, limit !== void 0 ? { limit } : void 0);
|
|
47
|
+
}
|
|
48
|
+
case OPENAI_TOOL_REMEMBER: {
|
|
49
|
+
const text = String(a.text ?? "");
|
|
50
|
+
const path = typeof a.path === "string" ? a.path : void 0;
|
|
51
|
+
await client.remember(text, path !== void 0 ? { path } : void 0);
|
|
52
|
+
return { ok: true };
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
throw new Error(`dispatchOpenAiToolCall: unknown tool "${name}"`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
OPENAI_TOOL_RECALL,
|
|
60
|
+
OPENAI_TOOL_REMEMBER,
|
|
61
|
+
createOpenAiTools,
|
|
62
|
+
dispatchOpenAiToolCall
|
|
63
|
+
};
|
package/sdk/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|