Compare commits
31
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e16dadaa4 | ||
|
|
300a45c2aa | ||
|
|
f6d522a650 | ||
|
|
3485ea2541 | ||
|
|
12e5d2a217 | ||
|
|
086bcac64d | ||
|
|
552f9d19c8 | ||
|
|
cd2da82819 | ||
|
|
402f0d3dab | ||
|
|
2bf399c2ee | ||
|
|
71ad98c7e0 | ||
|
|
0017ee0877 | ||
|
|
1b7357d99a | ||
|
|
c88e6e4cac | ||
|
|
858809ec06 | ||
|
|
ac7c1fcd8c | ||
|
|
dc1a741642 | ||
|
|
729639a557 | ||
|
|
b66b36c080 | ||
|
|
b92346b696 | ||
|
|
28a7caa63b | ||
|
|
46a4db3b24 | ||
|
|
fd7f218488 | ||
|
|
d46e4b1e61 | ||
|
|
eb48593e6e | ||
|
|
838f8e9be1 | ||
|
|
ba8f119448 | ||
|
|
3ad390d834 | ||
|
|
514697a81f | ||
|
|
e2f5bd0380 | ||
|
|
d18e83b083 |
@@ -53,6 +53,8 @@ jobs:
|
||||
integrations-pipecat: ${{ steps.filter.outputs.integrations-pipecat }}
|
||||
integrations-agentcore: ${{ steps.filter.outputs.integrations-agentcore }}
|
||||
integrations-smolagents: ${{ steps.filter.outputs.integrations-smolagents }}
|
||||
tools-agent-sdk: ${{ steps.filter.outputs.tools-agent-sdk }}
|
||||
tools-self-driving-agents: ${{ steps.filter.outputs.tools-self-driving-agents }}
|
||||
dev: ${{ steps.filter.outputs.dev }}
|
||||
ci: ${{ steps.filter.outputs.ci }}
|
||||
# Secrets are available for internal PRs, pull_request_review, and workflow_dispatch.
|
||||
@@ -145,6 +147,10 @@ jobs:
|
||||
- 'hindsight-integrations/agentcore/**'
|
||||
integrations-smolagents:
|
||||
- 'hindsight-integrations/smolagents/**'
|
||||
tools-agent-sdk:
|
||||
- 'hindsight-tools/hindsight-agent-sdk/**'
|
||||
tools-self-driving-agents:
|
||||
- 'hindsight-tools/self-driving-agents/**'
|
||||
dev:
|
||||
- 'hindsight-dev/**'
|
||||
ci:
|
||||
@@ -298,6 +304,9 @@ jobs:
|
||||
- name: Build hindsight-all-npm (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-all-npm
|
||||
|
||||
- name: Build hindsight-agent-sdk (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-tools/hindsight-agent-sdk
|
||||
|
||||
- name: Install openclaw dependencies
|
||||
working-directory: ./hindsight-integrations/openclaw
|
||||
run: npm ci
|
||||
@@ -361,6 +370,9 @@ jobs:
|
||||
- name: Build hindsight-all-npm (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-all-npm
|
||||
|
||||
- name: Build hindsight-agent-sdk (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-tools/hindsight-agent-sdk
|
||||
|
||||
- name: Install openclaw dependencies
|
||||
working-directory: ./hindsight-integrations/openclaw
|
||||
run: npm ci
|
||||
@@ -515,6 +527,72 @@ jobs:
|
||||
working-directory: ./hindsight-integrations/opencode
|
||||
run: npm run build
|
||||
|
||||
test-hindsight-agent-sdk:
|
||||
needs: [detect-changes]
|
||||
if: >-
|
||||
github.event_name != 'pull_request_review' &&
|
||||
(github.event_name == 'workflow_dispatch' ||
|
||||
needs.detect-changes.outputs.tools-agent-sdk == 'true' ||
|
||||
needs.detect-changes.outputs.ci == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install root workspace dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build hindsight-client (agent-sdk dep)
|
||||
run: npm run build --workspace=hindsight-clients/typescript
|
||||
|
||||
- name: Run tests
|
||||
run: npm test --workspace=hindsight-tools/hindsight-agent-sdk
|
||||
|
||||
- name: Build
|
||||
run: npm run build --workspace=hindsight-tools/hindsight-agent-sdk
|
||||
|
||||
test-self-driving-agents:
|
||||
needs: [detect-changes]
|
||||
if: >-
|
||||
github.event_name != 'pull_request_review' &&
|
||||
(github.event_name == 'workflow_dispatch' ||
|
||||
needs.detect-changes.outputs.tools-self-driving-agents == 'true' ||
|
||||
needs.detect-changes.outputs.ci == 'true')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha || '' }}
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: package-lock.json
|
||||
|
||||
- name: Install root workspace dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build hindsight-client (self-driving-agents dep)
|
||||
run: npm run build --workspace=hindsight-clients/typescript
|
||||
|
||||
- name: Run tests
|
||||
run: npm test --workspace=hindsight-tools/self-driving-agents
|
||||
|
||||
- name: Build
|
||||
run: npm run build --workspace=hindsight-tools/self-driving-agents
|
||||
|
||||
test-cloudflare-oauth-proxy-integration:
|
||||
needs: [detect-changes]
|
||||
if: >-
|
||||
@@ -1883,6 +1961,9 @@ jobs:
|
||||
- name: Build hindsight-all-npm (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-all-npm
|
||||
|
||||
- name: Build hindsight-agent-sdk (openclaw dep)
|
||||
run: npm run build --workspace=hindsight-tools/hindsight-agent-sdk
|
||||
|
||||
- name: Install openclaw integration dependencies
|
||||
working-directory: ./hindsight-integrations/openclaw
|
||||
run: npm ci
|
||||
@@ -3178,6 +3259,8 @@ jobs:
|
||||
- test-embed
|
||||
- test-embed-windows
|
||||
- test-hindsight-all
|
||||
- test-hindsight-agent-sdk
|
||||
- test-self-driving-agents
|
||||
- test-doc-examples
|
||||
- test-upgrade
|
||||
- verify-generated-files
|
||||
|
||||
+173
-156
@@ -1,15 +1,16 @@
|
||||
{
|
||||
"name": "@vectorize-io/hindsight-openclaw",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@vectorize-io/hindsight-openclaw",
|
||||
"version": "0.6.0",
|
||||
"version": "0.6.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@vectorize-io/hindsight-agent-sdk": "file:../../hindsight-tools/hindsight-agent-sdk",
|
||||
"@vectorize-io/hindsight-all": "^0.1.0",
|
||||
"@vectorize-io/hindsight-client": "^0.5.0"
|
||||
},
|
||||
@@ -27,6 +28,18 @@
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"../../hindsight-tools/hindsight-agent-sdk": {
|
||||
"name": "@vectorize-io/hindsight-agent-sdk",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vectorize-io/hindsight-client": "^0.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@clack/core": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-1.2.0.tgz",
|
||||
@@ -50,9 +63,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz",
|
||||
"integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==",
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -62,9 +75,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.9.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz",
|
||||
"integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==",
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -91,9 +104,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz",
|
||||
"integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -110,9 +123,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.124.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz",
|
||||
"integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==",
|
||||
"version": "0.127.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz",
|
||||
"integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -127,9 +140,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -144,9 +157,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -161,9 +174,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -178,9 +191,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -195,9 +208,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -212,9 +225,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -229,9 +242,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -246,9 +259,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -263,9 +276,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -280,9 +293,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -297,9 +310,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -314,9 +327,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -331,9 +344,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
@@ -341,18 +354,18 @@
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "1.9.2",
|
||||
"@emnapi/runtime": "1.9.2",
|
||||
"@napi-rs/wasm-runtime": "^1.1.3"
|
||||
"@emnapi/core": "1.10.0",
|
||||
"@emnapi/runtime": "1.10.0",
|
||||
"@napi-rs/wasm-runtime": "^1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -367,9 +380,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -384,9 +397,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -443,6 +456,10 @@
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vectorize-io/hindsight-agent-sdk": {
|
||||
"resolved": "../../hindsight-tools/hindsight-agent-sdk",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@vectorize-io/hindsight-all": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vectorize-io/hindsight-all/-/hindsight-all-0.1.0.tgz",
|
||||
@@ -453,22 +470,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vectorize-io/hindsight-client": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@vectorize-io/hindsight-client/-/hindsight-client-0.5.0.tgz",
|
||||
"integrity": "sha512-Ob4hSIpx1bb1BU0A7SDPQdFkDhJPi+haA1HoaQFrE2qz2VanSeoKulGEmnbH5RgVJuKRTjqQPAYrgiBN5r3Xlg==",
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@vectorize-io/hindsight-client/-/hindsight-client-0.5.6.tgz",
|
||||
"integrity": "sha512-VBMkCQP7dCy9BqkoqhZxxl5sVW6opKT3l6wexval7ZM4syTOGlmpu7BRhtFycxWmkWjXwH+XM6n4lzBoWTSPdA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz",
|
||||
"integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz",
|
||||
"integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.4",
|
||||
"@vitest/utils": "4.1.4",
|
||||
"@vitest/spy": "4.1.5",
|
||||
"@vitest/utils": "4.1.5",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -477,13 +494,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz",
|
||||
"integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz",
|
||||
"integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.4",
|
||||
"@vitest/spy": "4.1.5",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@@ -504,9 +521,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz",
|
||||
"integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz",
|
||||
"integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -517,13 +534,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz",
|
||||
"integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz",
|
||||
"integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.4",
|
||||
"@vitest/utils": "4.1.5",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -531,14 +548,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz",
|
||||
"integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz",
|
||||
"integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.4",
|
||||
"@vitest/utils": "4.1.4",
|
||||
"@vitest/pretty-format": "4.1.5",
|
||||
"@vitest/utils": "4.1.5",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@@ -547,9 +564,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz",
|
||||
"integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz",
|
||||
"integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -557,13 +574,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/ui": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.4.tgz",
|
||||
"integrity": "sha512-EgFR7nlj5iTDYZYCvavjFokNYwr3c3ry0sFiCg+N7B233Nwp+NNx7eoF/XvMWDCKY71xXAG3kFkt97ZHBJVL8A==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.5.tgz",
|
||||
"integrity": "sha512-3Z9HNFiV0IF1fk0JPiK+7kE1GcaIPefQQIBYur6PM5yFIq6agys3uqP/0t966e1wXfmjbRCHDe7qW236Xjwnag==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.4",
|
||||
"@vitest/utils": "4.1.5",
|
||||
"fflate": "^0.8.2",
|
||||
"flatted": "^3.4.2",
|
||||
"pathe": "^2.0.3",
|
||||
@@ -575,17 +592,17 @@
|
||||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vitest": "4.1.4"
|
||||
"vitest": "4.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz",
|
||||
"integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz",
|
||||
"integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.4",
|
||||
"@vitest/pretty-format": "4.1.5",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -631,9 +648,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
|
||||
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz",
|
||||
"integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -1067,9 +1084,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.9",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz",
|
||||
"integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==",
|
||||
"version": "8.5.12",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz",
|
||||
"integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -1096,14 +1113,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.15",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz",
|
||||
"integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==",
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.124.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.15"
|
||||
"@oxc-project/types": "=0.127.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.17"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
@@ -1112,21 +1129,21 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.15",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.15",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15"
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17"
|
||||
}
|
||||
},
|
||||
"node_modules/siginfo": {
|
||||
@@ -1175,9 +1192,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/std-env": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz",
|
||||
"integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz",
|
||||
"integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -1189,9 +1206,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyexec": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz",
|
||||
"integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==",
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz",
|
||||
"integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1265,17 +1282,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.8",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz",
|
||||
"integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==",
|
||||
"version": "8.0.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz",
|
||||
"integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.8",
|
||||
"rolldown": "1.0.0-rc.15",
|
||||
"tinyglobby": "^0.2.15"
|
||||
"postcss": "^8.5.10",
|
||||
"rolldown": "1.0.0-rc.17",
|
||||
"tinyglobby": "^0.2.16"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
@@ -1343,19 +1360,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz",
|
||||
"integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz",
|
||||
"integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.4",
|
||||
"@vitest/mocker": "4.1.4",
|
||||
"@vitest/pretty-format": "4.1.4",
|
||||
"@vitest/runner": "4.1.4",
|
||||
"@vitest/snapshot": "4.1.4",
|
||||
"@vitest/spy": "4.1.4",
|
||||
"@vitest/utils": "4.1.4",
|
||||
"@vitest/expect": "4.1.5",
|
||||
"@vitest/mocker": "4.1.5",
|
||||
"@vitest/pretty-format": "4.1.5",
|
||||
"@vitest/runner": "4.1.5",
|
||||
"@vitest/snapshot": "4.1.5",
|
||||
"@vitest/spy": "4.1.5",
|
||||
"@vitest/utils": "4.1.5",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
@@ -1383,12 +1400,12 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.4",
|
||||
"@vitest/browser-preview": "4.1.4",
|
||||
"@vitest/browser-webdriverio": "4.1.4",
|
||||
"@vitest/coverage-istanbul": "4.1.4",
|
||||
"@vitest/coverage-v8": "4.1.4",
|
||||
"@vitest/ui": "4.1.4",
|
||||
"@vitest/browser-playwright": "4.1.5",
|
||||
"@vitest/browser-preview": "4.1.5",
|
||||
"@vitest/browser-webdriverio": "4.1.5",
|
||||
"@vitest/coverage-istanbul": "4.1.5",
|
||||
"@vitest/coverage-v8": "4.1.5",
|
||||
"@vitest/ui": "4.1.5",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
@@ -46,8 +46,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@vectorize-io/hindsight-client": "^0.5.0",
|
||||
"@vectorize-io/hindsight-all": "^0.1.0"
|
||||
"@vectorize-io/hindsight-agent-sdk": "file:../../hindsight-tools/hindsight-agent-sdk",
|
||||
"@vectorize-io/hindsight-all": "^0.1.0",
|
||||
"@vectorize-io/hindsight-client": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {
|
||||
MoltbotPluginAPI,
|
||||
PluginConfig,
|
||||
PluginHookAgentContext,
|
||||
PluginToolContext,
|
||||
MemoryResult,
|
||||
RetainRequest,
|
||||
} from "./types.js";
|
||||
@@ -14,8 +15,10 @@ import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import * as log from "./logger.js";
|
||||
import { configureLogger, setApiLogger, stopLogger } from "./logger.js";
|
||||
import { mkdirSync, readFileSync } from "fs";
|
||||
import { mkdirSync, readFileSync, writeFileSync, existsSync, readdirSync } from "fs";
|
||||
import { extname } from "path";
|
||||
import { homedir } from "os";
|
||||
import { createKnowledgeTools, TOOL_NAMES } from "@vectorize-io/hindsight-agent-sdk";
|
||||
|
||||
function loadPackageVersion(): string {
|
||||
try {
|
||||
@@ -1878,6 +1881,7 @@ export default function (api: MoltbotPluginAPI) {
|
||||
debug(
|
||||
`[Hindsight] before_agent_start - bank: ${bankId}, channel: ${resolvedCtx.messageProvider}/${resolvedCtx.channelId}`
|
||||
);
|
||||
|
||||
} catch (error) {
|
||||
log.warn(`before_agent_start identity resolution error: ${error}`);
|
||||
}
|
||||
@@ -2353,6 +2357,40 @@ ${memoriesFormatted}
|
||||
});
|
||||
debug("[Hindsight] Hooks registered");
|
||||
log.info("agent hooks registered");
|
||||
|
||||
// Register knowledge tools (opt-in via enableKnowledgeTools config flag)
|
||||
if (pluginConfig.enableKnowledgeTools && typeof api.registerTool === "function") {
|
||||
try {
|
||||
const apiUrl = (() => {
|
||||
const ext = detectExternalApi(pluginConfig);
|
||||
return ext?.apiUrl || `http://localhost:${pluginConfig.apiPort || 9077}`;
|
||||
})();
|
||||
const apiToken = pluginConfig.hindsightApiToken || undefined;
|
||||
|
||||
// Factory: called per session with agent context, returns tools scoped to that bank
|
||||
const factory = (ctx: PluginToolContext) => {
|
||||
const bankId = deriveBankId(ctx as any, pluginConfig);
|
||||
const tools = createKnowledgeTools({ apiUrl, apiToken, bankId });
|
||||
return tools.map((t) => ({
|
||||
name: t.name,
|
||||
label: t.label,
|
||||
description: t.description,
|
||||
parameters: t.parameters,
|
||||
async execute(_id: string, params: Record<string, unknown>) {
|
||||
return { ...await t.execute(params), details: {} };
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
api.registerTool(factory, {
|
||||
names: [...TOOL_NAMES],
|
||||
optional: false,
|
||||
});
|
||||
log.info("knowledge tools registered");
|
||||
} catch (err) {
|
||||
log.warn(`knowledge tools registration failed: ${err}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error("plugin loading error", error);
|
||||
if (error instanceof Error) {
|
||||
|
||||
@@ -14,13 +14,24 @@ export interface MoltbotPluginAPI {
|
||||
event: string,
|
||||
handler: (event: any, ctx?: any) => void | Promise<void | PluginPromptHookResult>
|
||||
): void;
|
||||
// Register a tool or tool factory for agents
|
||||
registerTool?(
|
||||
factory: (ctx: PluginToolContext) => any | any[] | null | undefined,
|
||||
opts?: { name?: string; names?: string[]; optional?: boolean },
|
||||
): void;
|
||||
// OpenClaw framework logger — handles coloring/formatting consistently across plugins
|
||||
logger: {
|
||||
info(msg: string): void;
|
||||
warn(msg: string): void;
|
||||
error(msg: string): void;
|
||||
};
|
||||
// Add more as needed
|
||||
}
|
||||
|
||||
export interface PluginToolContext {
|
||||
config?: MoltbotConfig;
|
||||
agentId?: string;
|
||||
sessionKey?: string;
|
||||
workspaceDir?: string;
|
||||
}
|
||||
|
||||
export interface MoltbotConfig {
|
||||
@@ -99,6 +110,7 @@ export interface PluginConfig {
|
||||
retainQueuePath?: string; // Path to JSONL file for buffering failed retains. Default: ~/.openclaw/data/hindsight-retain-queue.jsonl
|
||||
retainQueueMaxAgeMs?: number; // Max age in ms for queued items. -1 = keep forever (default: -1)
|
||||
retainQueueFlushIntervalMs?: number; // How often to attempt flushing the queue in ms. Default: 60000 (1 min)
|
||||
enableKnowledgeTools?: boolean; // Register agent_knowledge_* tools. Default: false. Set to true by the self-driving-agents CLI.
|
||||
}
|
||||
|
||||
export interface ServiceConfig {
|
||||
|
||||
+1286
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@vectorize-io/hindsight-agent-sdk",
|
||||
"version": "0.1.0",
|
||||
"description": "Agent knowledge tools powered by Hindsight — harness-agnostic SDK",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest run tests",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"ai-agents",
|
||||
"hindsight",
|
||||
"memory",
|
||||
"knowledge",
|
||||
"self-driving"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vectorize-io/hindsight.git",
|
||||
"directory": "hindsight-agent-sdk"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vectorize-io/hindsight-client": "^0.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* Hindsight Agent SDK — harness-agnostic knowledge tools.
|
||||
*
|
||||
* Provides agent_knowledge_* tool definitions that any harness can register.
|
||||
* Uses @vectorize-io/hindsight-client for all API calls.
|
||||
*/
|
||||
|
||||
import {
|
||||
HindsightClient,
|
||||
sdk,
|
||||
createClient,
|
||||
createConfig,
|
||||
type HindsightClientOptions,
|
||||
} from "@vectorize-io/hindsight-client";
|
||||
|
||||
// ── Types ──────────────────────────────────────────────
|
||||
|
||||
export interface KnowledgeTool {
|
||||
name: string;
|
||||
label: string;
|
||||
description: string;
|
||||
parameters: Record<string, unknown>;
|
||||
execute: (params: Record<string, unknown>) => Promise<KnowledgeToolResult>;
|
||||
}
|
||||
|
||||
export interface KnowledgeToolResult {
|
||||
content: Array<{ type: "text"; text: string }>;
|
||||
}
|
||||
|
||||
export interface CreateKnowledgeToolsOptions {
|
||||
/** Hindsight API base URL */
|
||||
apiUrl: string;
|
||||
/** Optional API token */
|
||||
apiToken?: string;
|
||||
/** Memory bank ID for this agent */
|
||||
bankId: string;
|
||||
}
|
||||
|
||||
// ── Constants ──────────────────────────────────────────
|
||||
|
||||
const PAGE_DEFAULTS = {
|
||||
mode: "delta" as const,
|
||||
refresh_after_consolidation: true,
|
||||
exclude_mental_models: true,
|
||||
fact_types: ["observation" as const],
|
||||
};
|
||||
|
||||
export const TOOL_NAMES = [
|
||||
"agent_knowledge_list_pages",
|
||||
"agent_knowledge_get_page",
|
||||
"agent_knowledge_create_page",
|
||||
"agent_knowledge_update_page",
|
||||
"agent_knowledge_delete_page",
|
||||
"agent_knowledge_recall",
|
||||
"agent_knowledge_ingest",
|
||||
] as const;
|
||||
|
||||
export type KnowledgeToolName = (typeof TOOL_NAMES)[number];
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────
|
||||
|
||||
function ok(data: unknown): KnowledgeToolResult {
|
||||
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
||||
}
|
||||
|
||||
// ── Factory ────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Create the full set of agent_knowledge_* tools for a given bank.
|
||||
*
|
||||
* Returns harness-agnostic tool definitions. Each harness adapter
|
||||
* wraps these into its native tool format.
|
||||
*/
|
||||
export function createKnowledgeTools(opts: CreateKnowledgeToolsOptions): KnowledgeTool[] {
|
||||
const client = new HindsightClient({
|
||||
baseUrl: opts.apiUrl,
|
||||
apiKey: opts.apiToken,
|
||||
userAgent: "hindsight-agent-sdk/0.1.0",
|
||||
});
|
||||
const lowLevel = createClient(
|
||||
createConfig({
|
||||
baseUrl: opts.apiUrl,
|
||||
headers: {
|
||||
...(opts.apiToken ? { Authorization: `Bearer ${opts.apiToken}` } : {}),
|
||||
"User-Agent": "hindsight-agent-sdk/0.1.0",
|
||||
},
|
||||
})
|
||||
);
|
||||
const bankId = opts.bankId;
|
||||
|
||||
return [
|
||||
{
|
||||
name: "agent_knowledge_list_pages",
|
||||
label: "List knowledge pages",
|
||||
description:
|
||||
"List all your knowledge pages (IDs and names only). Use agent_knowledge_get_page to read the full content of a specific page.",
|
||||
parameters: { type: "object", properties: {} },
|
||||
async execute() {
|
||||
const resp = await sdk.listMentalModels({
|
||||
client: lowLevel,
|
||||
path: { bank_id: bankId },
|
||||
query: { detail: "metadata" },
|
||||
});
|
||||
return ok(resp.data);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_get_page",
|
||||
label: "Read a knowledge page",
|
||||
description:
|
||||
"Read a specific knowledge page by its ID. Returns the full synthesized content.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
page_id: { type: "string", description: "Page ID (e.g. 'user-preferences')" },
|
||||
},
|
||||
required: ["page_id"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
const result = await client.getMentalModel(bankId, params.page_id as string);
|
||||
return ok(result);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_create_page",
|
||||
label: "Create a knowledge page",
|
||||
description:
|
||||
"Create a new knowledge page. The source_query is a question the system re-asks after each consolidation to rebuild the page from conversation observations. " +
|
||||
"Pages auto-update as you have more conversations. Use for: user preferences, procedures, performance data, best practices.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
page_id: {
|
||||
type: "string",
|
||||
description: "Unique page ID, lowercase with hyphens (e.g. 'editorial-preferences')",
|
||||
},
|
||||
name: { type: "string", description: "Human-readable page name" },
|
||||
source_query: {
|
||||
type: "string",
|
||||
description:
|
||||
"The question that rebuilds this page (e.g. 'What are the user\\'s editorial preferences?')",
|
||||
},
|
||||
},
|
||||
required: ["page_id", "name", "source_query"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
const resp = await sdk.createMentalModel({
|
||||
client: lowLevel,
|
||||
path: { bank_id: bankId },
|
||||
body: {
|
||||
id: params.page_id as string,
|
||||
name: params.name as string,
|
||||
source_query: params.source_query as string,
|
||||
max_tokens: 4096,
|
||||
trigger: PAGE_DEFAULTS,
|
||||
},
|
||||
});
|
||||
return ok(resp.data);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_update_page",
|
||||
label: "Update a knowledge page",
|
||||
description:
|
||||
"Update a page's name or source query. The content will re-synthesize on next consolidation.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
page_id: { type: "string", description: "Page ID to update" },
|
||||
name: { type: "string", description: "New name (optional)" },
|
||||
source_query: { type: "string", description: "New source query (optional)" },
|
||||
},
|
||||
required: ["page_id"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
const result = await client.updateMentalModel(bankId, params.page_id as string, {
|
||||
name: params.name as string | undefined,
|
||||
sourceQuery: params.source_query as string | undefined,
|
||||
});
|
||||
return ok(result);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_delete_page",
|
||||
label: "Delete a knowledge page",
|
||||
description: "Permanently delete a knowledge page.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: { page_id: { type: "string", description: "Page ID to delete" } },
|
||||
required: ["page_id"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
await client.deleteMentalModel(bankId, params.page_id as string);
|
||||
return ok({ success: true });
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_recall",
|
||||
label: "Search memories",
|
||||
description:
|
||||
"Search across all retained conversations and documents for specific facts, numbers, or details not covered by your knowledge pages.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
query: { type: "string", description: "What to search for" },
|
||||
max_results: { type: "number", description: "Max results (default 10)" },
|
||||
},
|
||||
required: ["query"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
const result = await client.recall(bankId, params.query as string, {
|
||||
maxTokens: (params.max_results as number | undefined) ?? 10,
|
||||
});
|
||||
return ok(result);
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "agent_knowledge_ingest",
|
||||
label: "Ingest a document",
|
||||
description:
|
||||
"Upload a document into your memory bank. Pass the full raw content — never summarize before ingesting. " +
|
||||
"The system handles chunking and fact extraction. The title becomes the document ID (re-ingesting replaces it).",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
title: { type: "string", description: "Document title (becomes the document ID)" },
|
||||
content: { type: "string", description: "Full raw document content" },
|
||||
},
|
||||
required: ["title", "content"],
|
||||
},
|
||||
async execute(params: Record<string, unknown>) {
|
||||
const docId = (params.title as string).toLowerCase().replace(/ /g, "-");
|
||||
const result = await client.retainBatch(
|
||||
bankId,
|
||||
[{ content: params.content as string, document_id: docId }],
|
||||
{ async: true }
|
||||
);
|
||||
return ok(result);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { createKnowledgeTools, TOOL_NAMES } from "../src/index.js";
|
||||
import type { KnowledgeTool } from "../src/index.js";
|
||||
|
||||
// Mock fetch globally — the SDK uses @vectorize-io/hindsight-client which calls fetch.
|
||||
// The generated client passes a Request object (not a plain URL string).
|
||||
const mockFetch = vi.fn();
|
||||
vi.stubGlobal("fetch", mockFetch);
|
||||
|
||||
function mockResponse(data: unknown, status = 200) {
|
||||
return Promise.resolve({
|
||||
ok: status >= 200 && status < 300,
|
||||
status,
|
||||
json: () => Promise.resolve(data),
|
||||
text: () => Promise.resolve(JSON.stringify(data)),
|
||||
headers: new Headers({ "content-type": "application/json" }),
|
||||
clone: function () {
|
||||
return this;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** Extract the URL string from the first argument (Request object or string). */
|
||||
function getUrl(call: any[]): string {
|
||||
const arg = call[0];
|
||||
return typeof arg === "string" ? arg : (arg?.url ?? String(arg));
|
||||
}
|
||||
|
||||
/** Extract request init/options from the fetch call. */
|
||||
function getOpts(call: any[]): any {
|
||||
const arg = call[0];
|
||||
if (typeof arg === "object" && arg?.method) return arg;
|
||||
return call[1] ?? {};
|
||||
}
|
||||
|
||||
/** Extract the body as a parsed object from a fetch call. */
|
||||
async function getBody(call: any[]): Promise<any> {
|
||||
const opts = getOpts(call);
|
||||
if (typeof opts.body === "string") return JSON.parse(opts.body);
|
||||
// Request objects have a .json() or .text() method
|
||||
if (typeof opts.json === "function") return opts.json();
|
||||
if (typeof opts.text === "function") return JSON.parse(await opts.text());
|
||||
return undefined;
|
||||
}
|
||||
|
||||
describe("createKnowledgeTools", () => {
|
||||
let tools: KnowledgeTool[];
|
||||
|
||||
beforeEach(() => {
|
||||
mockFetch.mockReset();
|
||||
tools = createKnowledgeTools({
|
||||
apiUrl: "http://localhost:9077",
|
||||
apiToken: "test-token",
|
||||
bankId: "test-bank",
|
||||
});
|
||||
});
|
||||
|
||||
it("returns all 7 tools", () => {
|
||||
expect(tools).toHaveLength(7);
|
||||
const names = tools.map((t) => t.name);
|
||||
expect(names).toEqual([...TOOL_NAMES]);
|
||||
});
|
||||
|
||||
it("each tool has required fields", () => {
|
||||
for (const tool of tools) {
|
||||
expect(tool.name).toBeTruthy();
|
||||
expect(tool.label).toBeTruthy();
|
||||
expect(tool.description).toBeTruthy();
|
||||
expect(tool.parameters).toBeDefined();
|
||||
expect(typeof tool.execute).toBe("function");
|
||||
}
|
||||
});
|
||||
|
||||
it("list_pages calls the correct endpoint", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ models: [] }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_list_pages")!;
|
||||
const result = await tool.execute({});
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledTimes(1);
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/mental-models");
|
||||
expect(url).toContain("detail=metadata");
|
||||
expect(result.content[0].type).toBe("text");
|
||||
});
|
||||
|
||||
it("get_page calls the correct endpoint", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ id: "my-page", content: "hello" }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_get_page")!;
|
||||
await tool.execute({ page_id: "my-page" });
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/mental-models/my-page");
|
||||
});
|
||||
|
||||
it("create_page sends correct body with defaults", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ id: "prefs" }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_create_page")!;
|
||||
await tool.execute({
|
||||
page_id: "prefs",
|
||||
name: "Preferences",
|
||||
source_query: "What are the user's preferences?",
|
||||
});
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/mental-models");
|
||||
const body = await getBody(mockFetch.mock.calls[0]);
|
||||
expect(body.id).toBe("prefs");
|
||||
expect(body.name).toBe("Preferences");
|
||||
expect(body.source_query).toBe("What are the user's preferences?");
|
||||
expect(body.max_tokens).toBe(4096);
|
||||
expect(body.trigger.mode).toBe("delta");
|
||||
expect(body.trigger.refresh_after_consolidation).toBe(true);
|
||||
expect(body.trigger.exclude_mental_models).toBe(true);
|
||||
expect(body.trigger.fact_types).toEqual(["observation"]);
|
||||
});
|
||||
|
||||
it("update_page sends PATCH", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ id: "prefs" }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_update_page")!;
|
||||
await tool.execute({ page_id: "prefs", name: "New Name" });
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
const opts = getOpts(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/mental-models/prefs");
|
||||
expect(opts.method).toBe("PATCH");
|
||||
});
|
||||
|
||||
it("delete_page sends DELETE", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({}));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_delete_page")!;
|
||||
const result = await tool.execute({ page_id: "old-page" });
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
const opts = getOpts(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/mental-models/old-page");
|
||||
expect(opts.method).toBe("DELETE");
|
||||
expect(JSON.parse(result.content[0].text)).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it("recall sends POST with query", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ results: [{ text: "found" }] }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_recall")!;
|
||||
await tool.execute({ query: "what happened?" });
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
const opts = getOpts(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/memories/recall");
|
||||
expect(opts.method).toBe("POST");
|
||||
});
|
||||
|
||||
it("ingest sends POST with content and document_id", async () => {
|
||||
mockFetch.mockReturnValueOnce(mockResponse({ status: "queued" }));
|
||||
|
||||
const tool = tools.find((t) => t.name === "agent_knowledge_ingest")!;
|
||||
await tool.execute({ title: "My Document", content: "Full text here" });
|
||||
|
||||
const url = getUrl(mockFetch.mock.calls[0]);
|
||||
expect(url).toContain("/v1/default/banks/test-bank/memories");
|
||||
const body = await getBody(mockFetch.mock.calls[0]);
|
||||
expect(body.items[0].document_id).toBe("my-document");
|
||||
expect(body.items[0].content).toBe("Full text here");
|
||||
expect(body.async).toBe(true);
|
||||
});
|
||||
|
||||
it("works without apiToken", () => {
|
||||
const noAuthTools = createKnowledgeTools({
|
||||
apiUrl: "http://localhost:9077",
|
||||
bankId: "test-bank",
|
||||
});
|
||||
expect(noAuthTools).toHaveLength(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe("TOOL_NAMES", () => {
|
||||
it("exports all 7 tool names", () => {
|
||||
expect(TOOL_NAMES).toHaveLength(7);
|
||||
expect(TOOL_NAMES).toContain("agent_knowledge_list_pages");
|
||||
expect(TOOL_NAMES).toContain("agent_knowledge_ingest");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"declaration": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules/
|
||||
dist/
|
||||
@@ -0,0 +1,52 @@
|
||||
# @vectorize-io/self-driving-agents
|
||||
|
||||
Install self-driving agents with portable memory on any harness.
|
||||
|
||||
```bash
|
||||
npx @vectorize-io/self-driving-agents install ./my-agent --harness openclaw
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
1. Reads `bank-template.json` from the agent directory (knowledge pages, missions, directives)
|
||||
2. Reads `content/` directory for reference docs to ingest
|
||||
3. Resolves the Hindsight bank from the harness config
|
||||
4. Imports the template and ingests content
|
||||
5. Creates the harness agent, installs the skill, patches startup
|
||||
|
||||
## Agent directory layout
|
||||
|
||||
```
|
||||
my-agent/
|
||||
bank-template.json # optional: bank config + knowledge pages
|
||||
content/ # optional: reference docs (.md, .txt, .html, etc.)
|
||||
```
|
||||
|
||||
Agent name defaults to the directory name. Override with `--agent <name>`.
|
||||
|
||||
## Options
|
||||
|
||||
```
|
||||
npx @vectorize-io/self-driving-agents install <dir> --harness <harness> [options]
|
||||
|
||||
--harness <h> Required. openclaw | hermes | claude-code
|
||||
--agent <name> Agent name (defaults to directory name)
|
||||
--api-url <url> Override Hindsight API URL
|
||||
--api-token <t> Override API token
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```bash
|
||||
# Clone an agent repo
|
||||
git clone https://github.com/vectorize-io/self-driving-agents
|
||||
cd self-driving-agents
|
||||
|
||||
# Install the SEO blog writer
|
||||
npx @vectorize-io/self-driving-agents install ./marketing-seo-blog-posts --harness openclaw
|
||||
|
||||
# Create and start the agent
|
||||
openclaw agents add marketing-seo-blog-posts --workspace ~/.hindsight-agents/openclaw/marketing-seo-blog-posts --non-interactive
|
||||
openclaw gateway restart
|
||||
openclaw tui --session agent:marketing-seo-blog-posts:main:session1
|
||||
```
|
||||
+1342
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@vectorize-io/self-driving-agents",
|
||||
"version": "0.1.0",
|
||||
"description": "Install self-driving agents with portable memory on any harness",
|
||||
"type": "module",
|
||||
"main": "dist/cli.js",
|
||||
"bin": {
|
||||
"self-driving-agents": "dist/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"skill"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "vitest run tests",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"ai-agents",
|
||||
"self-driving",
|
||||
"hindsight",
|
||||
"memory",
|
||||
"openclaw",
|
||||
"hermes",
|
||||
"claude-code"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vectorize-io/hindsight.git",
|
||||
"directory": "hindsight-agent-setup"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4",
|
||||
"vitest": "^4.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@vectorize-io/hindsight-client": "^0.5.6"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
name: agent-knowledge
|
||||
description: Your long-term knowledge pages. Read them at session start. Create new pages when you learn something worth remembering across sessions. Pages auto-update from your conversations via Hindsight.
|
||||
---
|
||||
|
||||
# Agent Knowledge
|
||||
|
||||
You have knowledge pages that persist across sessions and auto-update from your conversations.
|
||||
|
||||
**How it works:** Your conversations are automatically retained into a Hindsight memory bank. The system extracts observations and uses them to keep your pages current. Each page has a "source query" — a question the system re-answers after every consolidation cycle to rebuild the page content. You create pages; the system maintains them.
|
||||
|
||||
## At session start
|
||||
|
||||
Call `agent_knowledge_list_pages` to see what pages exist, then `agent_knowledge_get_page` for each one you need.
|
||||
|
||||
## Reading
|
||||
|
||||
- `agent_knowledge_list_pages()` — list page IDs and names (no content)
|
||||
- `agent_knowledge_get_page(page_id)` — read the full content of a page
|
||||
|
||||
## Creating pages
|
||||
|
||||
When you learn something durable — a user preference, a working procedure, performance data — create a page immediately.
|
||||
|
||||
`agent_knowledge_create_page(page_id, name, source_query)`
|
||||
|
||||
- `page_id`: lowercase with hyphens (`editorial-preferences`)
|
||||
- `source_query`: a question that produces the page content from observations
|
||||
|
||||
Examples:
|
||||
|
||||
- `"What are the user's preferences for tone, length, and formatting?"`
|
||||
- `"What content strategies have performed well or poorly? Include numbers."`
|
||||
- `"What are the best practices for [topic], preferring our data over generic advice?"`
|
||||
|
||||
## Searching memories
|
||||
|
||||
`agent_knowledge_recall(query)` — search across all retained conversations and documents for specific facts.
|
||||
|
||||
Use when pages don't cover what you need.
|
||||
|
||||
## Ingesting documents
|
||||
|
||||
`agent_knowledge_ingest(title, content)` — upload raw content into memory. Never summarize before ingesting. Save large content to a file first, read it, then pass the full text.
|
||||
|
||||
## Updating and deleting
|
||||
|
||||
- `agent_knowledge_update_page(page_id, name?, source_query?)` — change what a page tracks
|
||||
- `agent_knowledge_delete_page(page_id)` — remove a page
|
||||
|
||||
## Important
|
||||
|
||||
- Pages update automatically — don't edit content directly
|
||||
- State preferences clearly in your responses so the system captures them
|
||||
- Create pages silently — don't announce it to the user
|
||||
- Prefer fewer broad pages over many narrow ones
|
||||
@@ -0,0 +1,465 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* self-driving-agents — install a self-driving agent.
|
||||
*
|
||||
* npx @vectorize-io/self-driving-agents install <agent> --harness openclaw [--agent <name>]
|
||||
*
|
||||
* Agent resolution:
|
||||
* marketing-agent → vectorize-io/self-driving-agents/marketing-agent (default repo)
|
||||
* my-org/my-repo/my-agent → my-org/my-repo/my-agent on GitHub
|
||||
* ./local-dir → local directory
|
||||
* /absolute/path → local directory
|
||||
*
|
||||
* Directory layout (recursive):
|
||||
* bank-template.json — optional: bank config at this level
|
||||
* *.md, *.txt, ... — content files (found recursively, excluding bank-template.json)
|
||||
*/
|
||||
|
||||
import {
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
mkdirSync,
|
||||
existsSync,
|
||||
readdirSync,
|
||||
statSync,
|
||||
rmSync,
|
||||
} from "fs";
|
||||
import { join, resolve, extname, basename, relative, dirname } from "path";
|
||||
import { homedir, tmpdir } from "os";
|
||||
import { fileURLToPath } from "url";
|
||||
import { execSync } from "child_process";
|
||||
import * as p from "@clack/prompts";
|
||||
import color from "picocolors";
|
||||
import { HindsightClient, sdk, createClient, createConfig } from "@vectorize-io/hindsight-client";
|
||||
|
||||
const DEFAULT_REPO = "vectorize-io/self-driving-agents";
|
||||
|
||||
// ── Content discovery ──────────────────────────────────
|
||||
|
||||
const CONTENT_EXTS = new Set([".md", ".txt", ".html", ".json", ".csv", ".xml"]);
|
||||
const IGNORED_FILES = new Set(["bank-template.json"]);
|
||||
|
||||
/** Recursively find all content files under `dir`, returning paths relative to `dir`. */
|
||||
function findContentFiles(dir: string): string[] {
|
||||
const results: string[] = [];
|
||||
function walk(current: string) {
|
||||
for (const entry of readdirSync(current)) {
|
||||
const full = join(current, entry);
|
||||
if (statSync(full).isDirectory()) {
|
||||
walk(full);
|
||||
} else if (CONTENT_EXTS.has(extname(entry).toLowerCase()) && !IGNORED_FILES.has(entry)) {
|
||||
results.push(relative(dir, full));
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(dir);
|
||||
return results.sort();
|
||||
}
|
||||
|
||||
// ── Agent resolution ───────────────────────────────────
|
||||
|
||||
function isLocalPath(input: string): boolean {
|
||||
return (
|
||||
input.startsWith("./") ||
|
||||
input.startsWith("../") ||
|
||||
input.startsWith("/") ||
|
||||
input.startsWith("~")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the agent specifier to a local directory.
|
||||
*
|
||||
* - Local paths (./foo, /foo, ~/foo) → resolve directly
|
||||
* - "name" → GitHub: vectorize-io/self-driving-agents/name
|
||||
* - "org/repo/path" → GitHub: org/repo/path
|
||||
*/
|
||||
async function resolveAgentDir(
|
||||
input: string,
|
||||
spinner: ReturnType<typeof p.spinner>
|
||||
): Promise<{ dir: string; source: string; cleanup?: () => void }> {
|
||||
if (isLocalPath(input)) {
|
||||
const dir = resolve(input.replace(/^~/, homedir()));
|
||||
if (!existsSync(dir)) throw new Error(`Directory not found: ${dir}`);
|
||||
return { dir, source: dir };
|
||||
}
|
||||
|
||||
// Parse GitHub reference: "name" or "org/repo/path/to/agent"
|
||||
const parts = input.split("/");
|
||||
let org: string, repo: string, subpath: string;
|
||||
|
||||
if (parts.length === 1) {
|
||||
// Just a name → default repo
|
||||
org = "vectorize-io";
|
||||
repo = "self-driving-agents";
|
||||
subpath = parts[0];
|
||||
} else if (parts.length >= 3) {
|
||||
// org/repo/path...
|
||||
org = parts[0];
|
||||
repo = parts[1];
|
||||
subpath = parts.slice(2).join("/");
|
||||
} else {
|
||||
throw new Error(
|
||||
`Invalid agent reference: '${input}'\n` +
|
||||
` Use: <name>, <org>/<repo>/<path>, or a local path (./dir)`
|
||||
);
|
||||
}
|
||||
|
||||
spinner.start(`Fetching ${color.cyan(`${org}/${repo}/${subpath}`)} from GitHub...`);
|
||||
|
||||
const tmp = join(tmpdir(), `sda-${Date.now()}`);
|
||||
mkdirSync(tmp, { recursive: true });
|
||||
|
||||
try {
|
||||
// Download repo tarball and extract the specific subdirectory
|
||||
const tarballUrl = `https://github.com/${org}/${repo}/archive/refs/heads/main.tar.gz`;
|
||||
execSync(
|
||||
`curl -sL "${tarballUrl}" | tar xz -C "${tmp}" --strip-components=1 "${repo}-main/${subpath}"`,
|
||||
{ stdio: "pipe" }
|
||||
);
|
||||
} catch {
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
throw new Error(
|
||||
`Failed to fetch ${org}/${repo}/${subpath}\n` +
|
||||
` Make sure the repository and path exist on GitHub.`
|
||||
);
|
||||
}
|
||||
|
||||
const dir = join(tmp, subpath);
|
||||
if (!existsSync(dir)) {
|
||||
rmSync(tmp, { recursive: true, force: true });
|
||||
throw new Error(`Path '${subpath}' not found in ${org}/${repo}`);
|
||||
}
|
||||
|
||||
const source = `github.com/${org}/${repo}/${subpath}`;
|
||||
spinner.stop(`Fetched ${color.cyan(source)}`);
|
||||
|
||||
return { dir, source, cleanup: () => rmSync(tmp, { recursive: true, force: true }) };
|
||||
}
|
||||
|
||||
// ── Skill ───────────────────────────────────────────────
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const SKILL_PATH = join(__dirname, "..", "skill", "SKILL.md");
|
||||
const SKILL_MD = readFileSync(SKILL_PATH, "utf-8");
|
||||
|
||||
// ── Plugin management ───────────────────────────────────
|
||||
|
||||
const OPENCLAW_CONFIG_PATH = join(homedir(), ".openclaw", "openclaw.json");
|
||||
|
||||
function readOpenClawConfig(): any {
|
||||
if (!existsSync(OPENCLAW_CONFIG_PATH)) return null;
|
||||
return JSON.parse(readFileSync(OPENCLAW_CONFIG_PATH, "utf-8"));
|
||||
}
|
||||
|
||||
function enableKnowledgeTools(): void {
|
||||
const config = readOpenClawConfig();
|
||||
if (!config) return;
|
||||
const pc = config.plugins?.entries?.["hindsight-openclaw"]?.config;
|
||||
if (!pc) return;
|
||||
if (pc.enableKnowledgeTools === true) return;
|
||||
pc.enableKnowledgeTools = true;
|
||||
writeFileSync(OPENCLAW_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n");
|
||||
}
|
||||
|
||||
function isPluginInstalled(): boolean {
|
||||
const config = readOpenClawConfig();
|
||||
if (!config) return false;
|
||||
return (
|
||||
config.plugins?.entries?.["hindsight-openclaw"]?.enabled !== false &&
|
||||
config.plugins?.entries?.["hindsight-openclaw"] !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
function isPluginConfigured(): boolean {
|
||||
const config = readOpenClawConfig();
|
||||
if (!config) return false;
|
||||
const pc = config.plugins?.entries?.["hindsight-openclaw"]?.config || {};
|
||||
return !!(pc.hindsightApiUrl || pc.embedVersion || pc.llmProvider);
|
||||
}
|
||||
|
||||
function resolveFromPlugin(agentId: string): { apiUrl: string; bankId: string; apiToken?: string } {
|
||||
const config = readOpenClawConfig();
|
||||
if (!config) throw new Error("OpenClaw config not found");
|
||||
const pc = config.plugins?.entries?.["hindsight-openclaw"]?.config || {};
|
||||
|
||||
const apiUrl = pc.hindsightApiUrl || `http://localhost:${pc.apiPort || 9077}`;
|
||||
const apiToken = pc.hindsightApiToken || undefined;
|
||||
|
||||
let bankId: string;
|
||||
if (pc.dynamicBankId === false && pc.bankId) {
|
||||
bankId = pc.bankId;
|
||||
} else {
|
||||
const granularity: string[] = pc.dynamicBankGranularity || ["agent", "channel", "user"];
|
||||
const fieldMap: Record<string, string> = {
|
||||
agent: agentId,
|
||||
channel: "unknown",
|
||||
user: "anonymous",
|
||||
provider: "unknown",
|
||||
};
|
||||
const base = granularity.map((f) => encodeURIComponent(fieldMap[f] || "unknown")).join("::");
|
||||
bankId = pc.bankIdPrefix ? `${pc.bankIdPrefix}-${base}` : base;
|
||||
}
|
||||
|
||||
return { apiUrl, bankId, apiToken };
|
||||
}
|
||||
|
||||
function getPluginSummary(): string {
|
||||
const config = readOpenClawConfig();
|
||||
if (!config) return "Not found";
|
||||
const pc = config.plugins?.entries?.["hindsight-openclaw"]?.config || {};
|
||||
if (pc.hindsightApiUrl) return `External: ${pc.hindsightApiUrl}`;
|
||||
if (pc.embedVersion) return `Embedded v${pc.embedVersion}`;
|
||||
return "Not configured";
|
||||
}
|
||||
|
||||
function parseAgentsJson(raw: string): any[] {
|
||||
const clean = raw.replace(/\n?\x1b\[[0-9;]*m[^\n]*/g, "").trim();
|
||||
const arrStart = clean.indexOf("\n[");
|
||||
const jsonStr = arrStart >= 0 ? clean.slice(arrStart + 1) : clean.startsWith("[") ? clean : "[]";
|
||||
return JSON.parse(jsonStr);
|
||||
}
|
||||
|
||||
async function ensurePlugin(): Promise<void> {
|
||||
if (!isPluginInstalled()) {
|
||||
p.log.warn("Hindsight plugin not found. Installing...");
|
||||
try {
|
||||
execSync("openclaw plugins install @vectorize-io/hindsight-openclaw", { stdio: "inherit" });
|
||||
} catch {
|
||||
p.cancel(
|
||||
"Failed to install plugin. Run manually:\n openclaw plugins install @vectorize-io/hindsight-openclaw"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPluginConfigured()) {
|
||||
p.log.warn("Hindsight plugin needs configuration.");
|
||||
try {
|
||||
execSync("npx --yes --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup", {
|
||||
stdio: "inherit",
|
||||
});
|
||||
} catch {
|
||||
p.cancel(
|
||||
"Run the wizard manually:\n npx --yes --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
const summary = getPluginSummary();
|
||||
if (process.stdin.isTTY) {
|
||||
const ok = await p.confirm({
|
||||
message: `Hindsight: ${color.cyan(summary)}. Use this?\n${color.dim(" Changing this will affect all existing agents — one OpenClaw instance shares a single Hindsight instance.")}`,
|
||||
});
|
||||
if (p.isCancel(ok)) {
|
||||
p.cancel("Cancelled.");
|
||||
process.exit(0);
|
||||
}
|
||||
if (!ok) {
|
||||
p.log.info("Launching configuration wizard...");
|
||||
try {
|
||||
execSync(
|
||||
"npx --yes --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup",
|
||||
{ stdio: "inherit" }
|
||||
);
|
||||
} catch {
|
||||
p.cancel(
|
||||
"Configuration failed. Run manually:\n npx --yes --package @vectorize-io/hindsight-openclaw hindsight-openclaw-setup"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
p.log.info(`Hindsight: ${color.cyan(summary)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Main ────────────────────────────────────────────────
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
if (args.length < 1 || args[0] === "--help" || args[0] === "-h") {
|
||||
console.log(`
|
||||
${color.bold("self-driving-agents")} — install a self-driving agent
|
||||
|
||||
${color.dim("Usage:")}
|
||||
npx @vectorize-io/self-driving-agents install <agent> --harness <harness> [--agent <name>]
|
||||
|
||||
${color.dim("Agent sources:")}
|
||||
${color.cyan("marketing-agent")} → ${DEFAULT_REPO}/marketing-agent
|
||||
${color.cyan("org/repo/my-agent")} → org/repo/my-agent on GitHub
|
||||
${color.cyan("./local-dir")} → local directory
|
||||
|
||||
${color.dim("Options:")}
|
||||
${color.cyan("--harness <h>")} Required. openclaw | hermes | claude-code
|
||||
${color.cyan("--agent <name>")} Agent name (defaults to directory name)
|
||||
`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
let dirArg = args[0] === "install" ? args[1] : args[0];
|
||||
const restArgs = args[0] === "install" ? args.slice(2) : args.slice(1);
|
||||
|
||||
if (!dirArg) {
|
||||
p.cancel("Agent argument required.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let harness: string | undefined;
|
||||
let agentName: string | undefined;
|
||||
|
||||
for (let i = 0; i < restArgs.length; i++) {
|
||||
if (restArgs[i] === "--harness" && restArgs[i + 1]) harness = restArgs[++i];
|
||||
else if (restArgs[i] === "--agent" && restArgs[i + 1]) agentName = restArgs[++i];
|
||||
}
|
||||
|
||||
if (!harness) {
|
||||
p.cancel("--harness required (openclaw | hermes | claude-code)");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
p.intro(color.bgCyan(color.black(` self-driving-agents `)));
|
||||
|
||||
// Step 0: Resolve agent directory (local or GitHub)
|
||||
const spin = p.spinner();
|
||||
const { dir, source, cleanup } = await resolveAgentDir(dirArg, spin);
|
||||
|
||||
try {
|
||||
const agentId = agentName || basename(dir);
|
||||
|
||||
// Step 1: Ensure plugin
|
||||
if (harness === "openclaw") {
|
||||
await ensurePlugin();
|
||||
enableKnowledgeTools();
|
||||
}
|
||||
|
||||
// Step 2: Resolve bank + API from plugin config
|
||||
const { apiUrl, bankId, apiToken } = resolveFromPlugin(agentId);
|
||||
|
||||
const workspaceDir = join(homedir(), ".self-driving-agents", "openclaw", agentId);
|
||||
|
||||
p.log.info(
|
||||
[
|
||||
`Agent: ${color.bold(agentId)}`,
|
||||
`Source: ${color.dim(source)}`,
|
||||
`Bank: ${color.dim(bankId)}`,
|
||||
`API: ${color.dim(apiUrl)}`,
|
||||
`Workspace: ${color.dim(workspaceDir)}`,
|
||||
].join("\n")
|
||||
);
|
||||
|
||||
// Step 3: Create client + health check
|
||||
const client = new HindsightClient({
|
||||
baseUrl: apiUrl,
|
||||
apiKey: apiToken,
|
||||
userAgent: "self-driving-agents/0.1.0",
|
||||
});
|
||||
const lowLevel = createClient(
|
||||
createConfig({
|
||||
baseUrl: apiUrl,
|
||||
headers: {
|
||||
...(apiToken ? { Authorization: `Bearer ${apiToken}` } : {}),
|
||||
"User-Agent": "self-driving-agents/0.1.0",
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
spin.start("Connecting to Hindsight...");
|
||||
try {
|
||||
await sdk.healthEndpointHealthGet({ client: lowLevel });
|
||||
spin.stop("Connected to Hindsight");
|
||||
} catch {
|
||||
spin.stop("Connection failed");
|
||||
p.cancel(`Cannot reach Hindsight at ${apiUrl}\nStart the server or reconfigure the plugin.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Step 4: Import bank template
|
||||
const templatePath = join(dir, "bank-template.json");
|
||||
if (existsSync(templatePath)) {
|
||||
spin.start("Importing bank template...");
|
||||
const template = JSON.parse(readFileSync(templatePath, "utf-8"));
|
||||
await sdk.importBankTemplate({
|
||||
client: lowLevel,
|
||||
path: { bank_id: bankId },
|
||||
body: template,
|
||||
});
|
||||
spin.stop("Bank template imported");
|
||||
}
|
||||
|
||||
// Step 5: Ingest content (recursive — all text files except bank-template.json)
|
||||
const contentFiles = findContentFiles(dir);
|
||||
if (contentFiles.length > 0) {
|
||||
spin.start(`Ingesting ${contentFiles.length} file(s)...`);
|
||||
for (const relPath of contentFiles) {
|
||||
const content = readFileSync(join(dir, relPath), "utf-8");
|
||||
if (!content.trim()) continue;
|
||||
// Use relative path (without extension) as document ID, e.g. "seo/keyword-research"
|
||||
const docId = relPath.replace(/\.[^.]+$/, "");
|
||||
await client.retainBatch(bankId, [{ content, document_id: docId }], { async: true });
|
||||
spin.message(`Ingesting ${relPath}...`);
|
||||
}
|
||||
spin.stop(`Ingested ${contentFiles.length} file(s)`);
|
||||
}
|
||||
|
||||
// Step 6: Create agent + install skill
|
||||
mkdirSync(workspaceDir, { recursive: true });
|
||||
|
||||
const skillDir = join(workspaceDir, "skills", "agent-knowledge");
|
||||
mkdirSync(skillDir, { recursive: true });
|
||||
writeFileSync(join(skillDir, "SKILL.md"), SKILL_MD);
|
||||
p.log.success("Knowledge skill installed");
|
||||
|
||||
if (harness === "openclaw") {
|
||||
try {
|
||||
const listOut = execSync("openclaw agents list --json 2>/dev/null", { encoding: "utf-8" });
|
||||
const agents = parseAgentsJson(listOut);
|
||||
if (!agents.some((a: any) => a.name === agentId || a.id === agentId)) {
|
||||
execSync(`openclaw agents add ${agentId} --workspace ${workspaceDir} --non-interactive`, {
|
||||
stdio: "pipe",
|
||||
});
|
||||
p.log.success(`Agent '${agentId}' created`);
|
||||
} else {
|
||||
p.log.info(`Agent '${agentId}' already exists`);
|
||||
}
|
||||
} catch {
|
||||
p.log.warn(
|
||||
`Create agent manually:\n openclaw agents add ${agentId} --workspace ${workspaceDir} --non-interactive`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 7: Patch startup
|
||||
const startupFile = join(workspaceDir, "AGENTS.md");
|
||||
if (existsSync(startupFile)) {
|
||||
let text = readFileSync(startupFile, "utf-8");
|
||||
if (!text.includes("agent-knowledge")) {
|
||||
text = text.replace(
|
||||
"Don't ask permission. Just do it.",
|
||||
"5. Read `skills/agent-knowledge/SKILL.md` and **execute its mandatory startup sequence**\n\nDon't ask permission. Just do it."
|
||||
);
|
||||
writeFileSync(startupFile, text);
|
||||
p.log.success("Startup patched");
|
||||
}
|
||||
}
|
||||
|
||||
p.note(
|
||||
[
|
||||
`${color.dim("1.")} openclaw gateway restart`,
|
||||
`${color.dim("2.")} openclaw tui --session agent:${agentId}:main:session1`,
|
||||
].join("\n"),
|
||||
"Next steps"
|
||||
);
|
||||
|
||||
p.outro(color.green(`'${agentId}' is ready`));
|
||||
} finally {
|
||||
cleanup?.();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
p.cancel(err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { mkdtemp, rm, writeFile, mkdir } from "fs/promises";
|
||||
import { tmpdir } from "os";
|
||||
import { join } from "path";
|
||||
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "fs";
|
||||
import { extname, relative, basename } from "path";
|
||||
|
||||
// ── Extracted helpers (mirroring cli.ts logic for unit testing) ──
|
||||
|
||||
const CONTENT_EXTS = new Set([".md", ".txt", ".html", ".json", ".csv", ".xml"]);
|
||||
const IGNORED_FILES = new Set(["bank-template.json"]);
|
||||
|
||||
function findContentFiles(dir: string): string[] {
|
||||
const results: string[] = [];
|
||||
function walk(current: string) {
|
||||
for (const entry of readdirSync(current)) {
|
||||
const full = join(current, entry);
|
||||
if (statSync(full).isDirectory()) {
|
||||
walk(full);
|
||||
} else if (CONTENT_EXTS.has(extname(entry).toLowerCase()) && !IGNORED_FILES.has(entry)) {
|
||||
results.push(relative(dir, full));
|
||||
}
|
||||
}
|
||||
}
|
||||
walk(dir);
|
||||
return results.sort();
|
||||
}
|
||||
|
||||
function isLocalPath(input: string): boolean {
|
||||
return (
|
||||
input.startsWith("./") ||
|
||||
input.startsWith("../") ||
|
||||
input.startsWith("/") ||
|
||||
input.startsWith("~")
|
||||
);
|
||||
}
|
||||
|
||||
function parseAgentsJson(raw: string): any[] {
|
||||
const clean = raw.replace(/\n?\x1b\[[0-9;]*m[^\n]*/g, "").trim();
|
||||
const arrStart = clean.indexOf("\n[");
|
||||
const jsonStr = arrStart >= 0 ? clean.slice(arrStart + 1) : clean.startsWith("[") ? clean : "[]";
|
||||
return JSON.parse(jsonStr);
|
||||
}
|
||||
|
||||
function resolveFromPluginConfig(
|
||||
agentId: string,
|
||||
pc: Record<string, any>
|
||||
): { apiUrl: string; bankId: string; apiToken?: string } {
|
||||
const apiUrl = pc.hindsightApiUrl || `http://localhost:${pc.apiPort || 9077}`;
|
||||
const apiToken = pc.hindsightApiToken || undefined;
|
||||
|
||||
let bankId: string;
|
||||
if (pc.dynamicBankId === false && pc.bankId) {
|
||||
bankId = pc.bankId;
|
||||
} else {
|
||||
const granularity: string[] = pc.dynamicBankGranularity || ["agent", "channel", "user"];
|
||||
const fieldMap: Record<string, string> = {
|
||||
agent: agentId,
|
||||
channel: "unknown",
|
||||
user: "anonymous",
|
||||
provider: "unknown",
|
||||
};
|
||||
const base = granularity.map((f) => encodeURIComponent(fieldMap[f] || "unknown")).join("::");
|
||||
bankId = pc.bankIdPrefix ? `${pc.bankIdPrefix}-${base}` : base;
|
||||
}
|
||||
|
||||
return { apiUrl, bankId, apiToken };
|
||||
}
|
||||
|
||||
// ── Tests ──
|
||||
|
||||
describe("findContentFiles", () => {
|
||||
let tmpDir: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tmpDir = await mkdtemp(join(tmpdir(), "sda-test-"));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("finds .md files recursively", async () => {
|
||||
await writeFile(join(tmpDir, "root.md"), "hello");
|
||||
await mkdir(join(tmpDir, "sub"));
|
||||
await writeFile(join(tmpDir, "sub", "nested.md"), "world");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["root.md", "sub/nested.md"]);
|
||||
});
|
||||
|
||||
it("finds multiple content extensions", async () => {
|
||||
await writeFile(join(tmpDir, "a.md"), "md");
|
||||
await writeFile(join(tmpDir, "b.txt"), "txt");
|
||||
await writeFile(join(tmpDir, "c.html"), "html");
|
||||
await writeFile(join(tmpDir, "d.csv"), "csv");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["a.md", "b.txt", "c.html", "d.csv"]);
|
||||
});
|
||||
|
||||
it("excludes bank-template.json", async () => {
|
||||
await writeFile(join(tmpDir, "bank-template.json"), "{}");
|
||||
await writeFile(join(tmpDir, "readme.md"), "hello");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["readme.md"]);
|
||||
});
|
||||
|
||||
it("excludes non-content files", async () => {
|
||||
await writeFile(join(tmpDir, "image.png"), "binary");
|
||||
await writeFile(join(tmpDir, "script.js"), "code");
|
||||
await writeFile(join(tmpDir, "doc.md"), "content");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["doc.md"]);
|
||||
});
|
||||
|
||||
it("handles deeply nested directories", async () => {
|
||||
await mkdir(join(tmpDir, "a", "b", "c"), { recursive: true });
|
||||
await writeFile(join(tmpDir, "a", "b", "c", "deep.md"), "deep");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["a/b/c/deep.md"]);
|
||||
});
|
||||
|
||||
it("returns empty for directory with no content", async () => {
|
||||
await writeFile(join(tmpDir, "bank-template.json"), "{}");
|
||||
await writeFile(join(tmpDir, "image.png"), "binary");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual([]);
|
||||
});
|
||||
|
||||
it("ignores bank-template.json in subdirectories too", async () => {
|
||||
await mkdir(join(tmpDir, "sub"));
|
||||
await writeFile(join(tmpDir, "sub", "bank-template.json"), "{}");
|
||||
await writeFile(join(tmpDir, "sub", "guide.md"), "content");
|
||||
|
||||
const files = findContentFiles(tmpDir);
|
||||
expect(files).toEqual(["sub/guide.md"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isLocalPath", () => {
|
||||
it("detects relative paths", () => {
|
||||
expect(isLocalPath("./my-agent")).toBe(true);
|
||||
expect(isLocalPath("../parent/agent")).toBe(true);
|
||||
});
|
||||
|
||||
it("detects absolute paths", () => {
|
||||
expect(isLocalPath("/Users/me/agent")).toBe(true);
|
||||
});
|
||||
|
||||
it("detects home paths", () => {
|
||||
expect(isLocalPath("~/dev/agent")).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects GitHub-style references", () => {
|
||||
expect(isLocalPath("marketing")).toBe(false);
|
||||
expect(isLocalPath("org/repo/path")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("parseAgentsJson", () => {
|
||||
it("parses clean JSON array", () => {
|
||||
const agents = parseAgentsJson('[{"id": "main"}]');
|
||||
expect(agents).toEqual([{ id: "main" }]);
|
||||
});
|
||||
|
||||
it("strips ANSI log lines before JSON", () => {
|
||||
const raw =
|
||||
"\x1b[38;5;103mhindsight:\x1b[0m plugin entry invoked\n" +
|
||||
'[\n {"id": "main"},\n {"id": "seo-writer", "name": "seo-writer"}\n]';
|
||||
const agents = parseAgentsJson(raw);
|
||||
expect(agents).toHaveLength(2);
|
||||
expect(agents[1].id).toBe("seo-writer");
|
||||
});
|
||||
|
||||
it("returns empty array for unparseable output", () => {
|
||||
const agents = parseAgentsJson("some random text");
|
||||
expect(agents).toEqual([]);
|
||||
});
|
||||
|
||||
it("handles multiple ANSI lines", () => {
|
||||
const raw = [
|
||||
"Config warnings:",
|
||||
"\x1b[35m[plugins]\x1b[39m registering plugin",
|
||||
"\x1b[35m[plugins]\x1b[39m hooks registered",
|
||||
'[{"id": "test"}]',
|
||||
].join("\n");
|
||||
const agents = parseAgentsJson(raw);
|
||||
expect(agents).toEqual([{ id: "test" }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveFromPluginConfig", () => {
|
||||
it("uses external API URL when set", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {
|
||||
hindsightApiUrl: "https://api.example.com",
|
||||
hindsightApiToken: "tok-123",
|
||||
dynamicBankGranularity: ["agent"],
|
||||
});
|
||||
expect(result.apiUrl).toBe("https://api.example.com");
|
||||
expect(result.apiToken).toBe("tok-123");
|
||||
expect(result.bankId).toBe("my-agent");
|
||||
});
|
||||
|
||||
it("falls back to localhost with apiPort", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {
|
||||
apiPort: 8888,
|
||||
dynamicBankGranularity: ["agent"],
|
||||
});
|
||||
expect(result.apiUrl).toBe("http://localhost:8888");
|
||||
expect(result.apiToken).toBeUndefined();
|
||||
});
|
||||
|
||||
it("defaults to port 9077", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {});
|
||||
expect(result.apiUrl).toBe("http://localhost:9077");
|
||||
});
|
||||
|
||||
it("computes bank ID with prefix", () => {
|
||||
const result = resolveFromPluginConfig("seo-writer", {
|
||||
bankIdPrefix: "nicolo",
|
||||
dynamicBankGranularity: ["agent"],
|
||||
});
|
||||
expect(result.bankId).toBe("nicolo-seo-writer");
|
||||
});
|
||||
|
||||
it("computes bank ID without prefix", () => {
|
||||
const result = resolveFromPluginConfig("seo-writer", {
|
||||
dynamicBankGranularity: ["agent"],
|
||||
});
|
||||
expect(result.bankId).toBe("seo-writer");
|
||||
});
|
||||
|
||||
it("uses multi-field granularity", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {
|
||||
dynamicBankGranularity: ["agent", "channel", "user"],
|
||||
});
|
||||
expect(result.bankId).toBe("my-agent::unknown::anonymous");
|
||||
});
|
||||
|
||||
it("uses default granularity when not specified", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {});
|
||||
expect(result.bankId).toBe("my-agent::unknown::anonymous");
|
||||
});
|
||||
|
||||
it("uses static bankId when dynamicBankId is false", () => {
|
||||
const result = resolveFromPluginConfig("my-agent", {
|
||||
dynamicBankId: false,
|
||||
bankId: "static-bank",
|
||||
});
|
||||
expect(result.bankId).toBe("static-bank");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "bundler",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Generated
+114
-4
@@ -9,12 +9,14 @@
|
||||
"hindsight-clients/typescript",
|
||||
"hindsight-control-plane",
|
||||
"hindsight-docs",
|
||||
"hindsight-all-npm"
|
||||
"hindsight-all-npm",
|
||||
"hindsight-tools/hindsight-agent-sdk",
|
||||
"hindsight-tools/self-driving-agents"
|
||||
]
|
||||
},
|
||||
"hindsight-all-npm": {
|
||||
"name": "@vectorize-io/hindsight-all",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.6",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
@@ -138,7 +140,7 @@
|
||||
},
|
||||
"hindsight-clients/typescript": {
|
||||
"name": "@vectorize-io/hindsight-client",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.6",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "0.88.0",
|
||||
@@ -357,7 +359,7 @@
|
||||
},
|
||||
"hindsight-control-plane": {
|
||||
"name": "@vectorize-io/hindsight-control-plane",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.6",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@chenglou/pretext": "^0.0.3",
|
||||
@@ -687,6 +689,34 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"hindsight-tools/hindsight-agent-sdk": {
|
||||
"name": "@vectorize-io/hindsight-agent-sdk",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vectorize-io/hindsight-client": "^0.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"hindsight-tools/self-driving-agents": {
|
||||
"name": "@vectorize-io/self-driving-agents",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/prompts": "^1.2.0",
|
||||
"@vectorize-io/hindsight-client": "^0.5.6"
|
||||
},
|
||||
"bin": {
|
||||
"self-driving-agents": "dist/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.4",
|
||||
"vitest": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@ai-sdk/gateway": {
|
||||
"version": "2.0.24",
|
||||
"resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.24.tgz",
|
||||
@@ -2964,6 +2994,28 @@
|
||||
"integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@clack/core": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-1.2.0.tgz",
|
||||
"integrity": "sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-wrap-ansi": "^0.1.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@clack/prompts": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.2.0.tgz",
|
||||
"integrity": "sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@clack/core": "1.2.0",
|
||||
"fast-string-width": "^1.1.0",
|
||||
"fast-wrap-ansi": "^0.1.3",
|
||||
"sisteransi": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||
@@ -5266,6 +5318,7 @@
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5283,6 +5336,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5300,6 +5354,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5317,6 +5372,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5334,6 +5390,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5351,6 +5408,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5368,6 +5426,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5385,6 +5444,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5402,6 +5462,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5419,6 +5480,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5436,6 +5498,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5453,6 +5516,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5470,6 +5534,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5487,6 +5552,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5504,6 +5570,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5521,6 +5588,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5538,6 +5606,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5555,6 +5624,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5572,6 +5642,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5589,6 +5660,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5606,6 +5678,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5623,6 +5696,7 @@
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5640,6 +5714,7 @@
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5657,6 +5732,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5674,6 +5750,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -5691,6 +5768,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -11265,6 +11343,10 @@
|
||||
"d3-transition": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@vectorize-io/hindsight-agent-sdk": {
|
||||
"resolved": "hindsight-tools/hindsight-agent-sdk",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@vectorize-io/hindsight-all": {
|
||||
"resolved": "hindsight-all-npm",
|
||||
"link": true
|
||||
@@ -11277,6 +11359,10 @@
|
||||
"resolved": "hindsight-control-plane",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@vectorize-io/self-driving-agents": {
|
||||
"resolved": "hindsight-tools/self-driving-agents",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@vercel/oidc": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.5.tgz",
|
||||
@@ -16617,6 +16703,21 @@
|
||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-string-truncated-width": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-1.2.1.tgz",
|
||||
"integrity": "sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-string-width": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-1.1.0.tgz",
|
||||
"integrity": "sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-string-truncated-width": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||
@@ -16633,6 +16734,15 @@
|
||||
],
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/fast-wrap-ansi": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.1.6.tgz",
|
||||
"integrity": "sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fast-string-width": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-xml-builder": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
|
||||
|
||||
+3
-1
@@ -5,7 +5,9 @@
|
||||
"hindsight-clients/typescript",
|
||||
"hindsight-control-plane",
|
||||
"hindsight-docs",
|
||||
"hindsight-all-npm"
|
||||
"hindsight-all-npm",
|
||||
"hindsight-tools/hindsight-agent-sdk",
|
||||
"hindsight-tools/self-driving-agents"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "./scripts/setup-hooks.sh"
|
||||
|
||||
@@ -69,19 +69,24 @@ for name, info in data.get("packages", {}).items():
|
||||
resolved = info.get("resolved", "")
|
||||
link = info.get("link")
|
||||
|
||||
if link is True:
|
||||
# Packages under hindsight-tools/ are monorepo workspace deps that
|
||||
# aren't published yet. The CI build pre-builds them before running
|
||||
# openclaw, so workspace resolution is expected and safe.
|
||||
is_tools_pkg = resolved.startswith(("../../hindsight-tools/", "file:../../hindsight-tools/"))
|
||||
|
||||
if link is True and not is_tools_pkg:
|
||||
# Workspace symlink, no registry URL. This is the bug that broke
|
||||
# the openclaw 0.6.0 release — npm had resolved a registry-ranged
|
||||
# dep to a workspace symlink because `npm install` was run from
|
||||
# the monorepo root.
|
||||
bad.append(f"{name}: (link=true — workspace symlink)")
|
||||
elif not resolved:
|
||||
elif not resolved and not is_tools_pkg:
|
||||
# Empty resolved on a non-link entry shouldn't happen, but flag
|
||||
# it anyway rather than silently accepting it.
|
||||
bad.append(f"{name}: (no `resolved` URL)")
|
||||
elif resolved.startswith("file:"):
|
||||
elif resolved.startswith("file:") and not is_tools_pkg:
|
||||
bad.append(f"{name}: {resolved}")
|
||||
elif resolved.startswith(("../", "./")):
|
||||
elif resolved.startswith(("../", "./")) and not is_tools_pkg:
|
||||
bad.append(f"{name}: {resolved}")
|
||||
|
||||
if bad:
|
||||
|
||||
@@ -91,6 +91,29 @@ if [ -d "$INTEGRATIONS_DIR" ] && { [ "$LINT_ALL" = "1" ] || [ -n "$CHANGED_FILES
|
||||
done
|
||||
fi
|
||||
|
||||
# Hindsight tools (Node packages under hindsight-tools/)
|
||||
TOOLS_DIR="$REPO_ROOT/hindsight-tools"
|
||||
if [ -n "$CI" ] || [ -n "$LINT_ALL_INTEGRATIONS" ]; then
|
||||
LINT_TOOLS_ALL=1
|
||||
TOOLS_CHANGED=""
|
||||
else
|
||||
LINT_TOOLS_ALL=0
|
||||
TOOLS_CHANGED=$( { git -C "$REPO_ROOT" diff --name-only HEAD -- "hindsight-tools/"; \
|
||||
git -C "$REPO_ROOT" ls-files --others --exclude-standard -- "hindsight-tools/"; } | sort -u )
|
||||
fi
|
||||
|
||||
if [ -d "$TOOLS_DIR" ] && { [ "$LINT_TOOLS_ALL" = "1" ] || [ -n "$TOOLS_CHANGED" ]; }; then
|
||||
for dir in "$TOOLS_DIR"/*/; do
|
||||
name=$(basename "$dir")
|
||||
if [ "$LINT_TOOLS_ALL" != "1" ]; then
|
||||
echo "$TOOLS_CHANGED" | grep -q "^hindsight-tools/$name/" || continue
|
||||
fi
|
||||
if [ -f "$dir/package.json" ]; then
|
||||
run_task "prettier-tool-$name" "$dir" "npx --yes prettier --write --config $REPO_ROOT/.prettierrc.json --ignore-path $REPO_ROOT/.gitignore ."
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Wait for all tasks to complete
|
||||
for pid in "${PIDS[@]}"; do
|
||||
wait "$pid" 2>/dev/null || true
|
||||
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_info() { echo -e "${YELLOW}$1${NC}"; }
|
||||
print_success() { echo -e "${GREEN}$1${NC}"; }
|
||||
print_error() { echo -e "${RED}$1${NC}" >&2; }
|
||||
|
||||
VALID_TOOLS=("self-driving-agents" "hindsight-agent-sdk")
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 <tool> <version>"
|
||||
echo " tool One of: ${VALID_TOOLS[*]}"
|
||||
echo " version Semver (e.g., 0.1.0, 1.0.0)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -ne 2 ]; then usage; fi
|
||||
|
||||
TOOL="$1"
|
||||
VERSION="$2"
|
||||
|
||||
# Validate tool name
|
||||
VALID=false
|
||||
for v in "${VALID_TOOLS[@]}"; do
|
||||
if [ "$v" = "$TOOL" ]; then VALID=true; break; fi
|
||||
done
|
||||
if [ "$VALID" = false ]; then
|
||||
print_error "Unknown tool: $TOOL"
|
||||
print_info "Valid tools: ${VALID_TOOLS[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate version format
|
||||
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
|
||||
print_error "Invalid version format: $VERSION (expected semver like 0.1.0)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve directory
|
||||
TOOL_DIR="hindsight-tools/$TOOL"
|
||||
if [ ! -d "$TOOL_DIR" ]; then
|
||||
print_error "Tool directory not found: $TOOL_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check we're on main
|
||||
BRANCH=$(git branch --show-current)
|
||||
if [ "$BRANCH" != "main" ]; then
|
||||
print_info "Warning: not on main branch (current: $BRANCH)"
|
||||
read -p "Continue? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 1; fi
|
||||
fi
|
||||
|
||||
# Check working tree is clean
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
print_error "Working tree is not clean. Commit or stash changes first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read current version
|
||||
if [ -f "$TOOL_DIR/package.json" ]; then
|
||||
CURRENT=$(grep '"version"' "$TOOL_DIR/package.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/')
|
||||
elif [ -f "$TOOL_DIR/pyproject.toml" ]; then
|
||||
CURRENT=$(grep '^version = ' "$TOOL_DIR/pyproject.toml" | sed 's/version = "\(.*\)"/\1/')
|
||||
else
|
||||
CURRENT="unknown"
|
||||
fi
|
||||
|
||||
print_info "Releasing $TOOL: $CURRENT → $VERSION"
|
||||
echo
|
||||
|
||||
# Update version in package manifest
|
||||
if [ -f "$TOOL_DIR/package.json" ]; then
|
||||
sed -i '' "s/\"version\": \"$CURRENT\"/\"version\": \"$VERSION\"/" "$TOOL_DIR/package.json"
|
||||
print_success "Updated package.json"
|
||||
elif [ -f "$TOOL_DIR/pyproject.toml" ]; then
|
||||
sed -i '' "s/version = \"$CURRENT\"/version = \"$VERSION\"/" "$TOOL_DIR/pyproject.toml"
|
||||
print_success "Updated pyproject.toml"
|
||||
fi
|
||||
|
||||
# Build
|
||||
if [ -f "$TOOL_DIR/package.json" ]; then
|
||||
(cd "$TOOL_DIR" && npm run build)
|
||||
print_success "Built"
|
||||
fi
|
||||
|
||||
# Commit, tag, push
|
||||
TAG="tools/$TOOL/v$VERSION"
|
||||
git add "$TOOL_DIR/"
|
||||
git commit -m "release($TOOL): v$VERSION"
|
||||
git tag "$TAG"
|
||||
git push origin main "$TAG"
|
||||
|
||||
print_success "Released $TOOL v$VERSION"
|
||||
print_info "Tag: $TAG"
|
||||
echo
|
||||
print_info "To publish to npm:"
|
||||
echo " cd $TOOL_DIR && npm publish --access public"
|
||||
Reference in New Issue
Block a user