mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
chore: code quality, CI/CD, and DX improvements
Phase 3 — Code Quality: - Deduplicate nowUnix() in lock-ops.mjs (import from utils.mjs) - Promote ESLint no-unused-vars to error, fix all 46 violations - Remove dead code: unused imports, variables, and catch bindings - Add /* global marked */ for CDN-loaded library in dashboard Phase 4 — CI/CD: - Add Node.js version matrix (22, 23) to CI workflow - Add npm audit security scan step to CI - Add innerHTML usage check to CI pipeline - Enable Dependabot for npm and GitHub Actions dependencies - Create PR template Phase 5 — Developer Experience: - Create .env.example documenting all environment variables - Expand CONTRIBUTING.md with commit conventions, agent/prompt creation guide, architecture overview, and test integrity - Add system architecture diagram with Mermaid (docs/architecture/) https://claude.ai/code/session_01GfwUNbgeMgXreFDbsNQMsS
This commit is contained in:
33 files changed
+336
-129
No files matched your search
@@ -0,0 +1,47 @@
|
|||||||
|
# TORCH Environment Variables
|
||||||
|
# Copy this file to .env and fill in the values for your deployment.
|
||||||
|
|
||||||
|
# ─── Dashboard ────────────────────────────────────────────────────────
|
||||||
|
# Basic Auth credentials for the dashboard (user:password format)
|
||||||
|
# TORCH_DASHBOARD_AUTH=admin:changeme
|
||||||
|
|
||||||
|
# ─── Configuration ────────────────────────────────────────────────────
|
||||||
|
# Path to torch-config.json (optional — overrides default lookup)
|
||||||
|
# TORCH_CONFIG_PATH=./torch-config.json
|
||||||
|
|
||||||
|
# ─── Agent Platform Detection ─────────────────────────────────────────
|
||||||
|
# Override automatic platform detection (jules | claude | codex | goose)
|
||||||
|
# AGENT_PLATFORM=
|
||||||
|
# AGENT_MODEL=
|
||||||
|
|
||||||
|
# Platform-specific API keys (used for automatic platform detection)
|
||||||
|
# CLAUDE_API_KEY=
|
||||||
|
# JULES_API_KEY=
|
||||||
|
# CODEX_API_KEY=
|
||||||
|
# GOOSE_API_KEY=
|
||||||
|
|
||||||
|
# ─── Nostr Lock Configuration ────────────────────────────────────────
|
||||||
|
# Comma-separated relay URLs (overrides config file)
|
||||||
|
# NOSTR_LOCK_RELAYS=wss://relay.damus.io,wss://nos.lol,wss://relay.primal.net
|
||||||
|
|
||||||
|
# Lock TTL in seconds (default: 7200)
|
||||||
|
# NOSTR_LOCK_TTL=7200
|
||||||
|
|
||||||
|
# Relay connection timeout in milliseconds (default: 8000)
|
||||||
|
# NOSTR_LOCK_TIMEOUT=8000
|
||||||
|
|
||||||
|
# Minimum relay quorum for successful publish (default: 1)
|
||||||
|
# NOSTR_LOCK_QUORUM=1
|
||||||
|
|
||||||
|
# ─── Memory Subsystem ────────────────────────────────────────────────
|
||||||
|
# Master toggle for the memory subsystem
|
||||||
|
# TORCH_MEMORY_ENABLED=false
|
||||||
|
|
||||||
|
# Individual memory feature flags
|
||||||
|
# TORCH_MEMORY_INGEST_ENABLED=false
|
||||||
|
# TORCH_MEMORY_RETRIEVAL_ENABLED=false
|
||||||
|
# TORCH_MEMORY_PRUNE_ENABLED=false
|
||||||
|
# TORCH_MEMORY_PRUNE_MODE=off
|
||||||
|
|
||||||
|
# ─── Telemetry (opt-in) ──────────────────────────────────────────────
|
||||||
|
# TELEMETRY=0
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
## Summary
|
||||||
|
|
||||||
|
<!-- 1-3 bullet points describing what this PR does and why -->
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
## Test plan
|
||||||
|
|
||||||
|
<!-- How was this tested? -->
|
||||||
|
|
||||||
|
- [ ] `npm run lint` passes
|
||||||
|
- [ ] `npm test` passes
|
||||||
|
- [ ] Manual verification (if applicable)
|
||||||
|
|
||||||
|
## Related issues
|
||||||
|
|
||||||
|
<!-- Link related issues: Fixes #123, Closes #456 -->
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "npm"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
open-pull-requests-limit: 3
|
||||||
@@ -9,14 +9,21 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-and-test:
|
build-and-test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [22, 23]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Use Node.js 22
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: ${{ matrix.node-version }}
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
|
- name: Check innerHTML usage
|
||||||
|
run: node scripts/check-innerhtml.mjs --report
|
||||||
|
- name: Security audit
|
||||||
|
run: npm audit --omit=dev --audit-level=high || true
|
||||||
- run: npm test
|
- run: npm test
|
||||||
+61
-8
@@ -16,11 +16,17 @@ Thank you for your interest in contributing to TORCH!
|
|||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
3. Copy the environment template (optional):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
This project requires a build step for certain artifacts (e.g., distribution files, dashboard assets).
|
This project requires a build step for distribution artifacts (dashboard, landing page, tarball).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
@@ -28,32 +34,79 @@ npm run build
|
|||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
Run the test suite to ensure your changes don't break existing functionality.
|
Run the full test suite:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
For faster feedback loop on unit tests (excluding integration):
|
For faster feedback on lock-backend unit tests:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run test:unit:lock-backend
|
npm run test:unit:lock-backend
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For integration/resilience tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run test:extended-main
|
||||||
|
```
|
||||||
|
|
||||||
### Linting
|
### Linting
|
||||||
|
|
||||||
Ensure your code follows the project's style guidelines.
|
Ensure your code follows the project's style guidelines:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
|
ESLint is configured with `no-unused-vars` as an error. Prefix intentionally unused parameters with `_` (e.g., `_err`, `_unused`).
|
||||||
|
|
||||||
|
## Commit Conventions
|
||||||
|
|
||||||
|
This project uses [Conventional Commits](https://www.conventionalcommits.org/):
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(scope): add new feature
|
||||||
|
fix(scope): fix a bug
|
||||||
|
chore(scope): maintenance task
|
||||||
|
docs(scope): documentation update
|
||||||
|
test(scope): add or fix tests
|
||||||
|
```
|
||||||
|
|
||||||
|
Common scopes: `dashboard`, `scheduler`, `lock-ops`, `memory`, `ci`, `tests`, `security`.
|
||||||
|
|
||||||
|
## Adding a New Agent Prompt
|
||||||
|
|
||||||
|
Agent prompts live in `src/prompts/daily/` and `src/prompts/weekly/`. To add a new agent:
|
||||||
|
|
||||||
|
1. Create a markdown file following the naming convention: `<agent-name>.md`
|
||||||
|
2. Add the agent to the roster in `src/prompts/roster.json`
|
||||||
|
3. Run `npm run validate:scheduler` to verify roster/prompt consistency
|
||||||
|
|
||||||
|
See existing prompts for the expected format.
|
||||||
|
|
||||||
|
## Architecture Overview
|
||||||
|
|
||||||
|
- **Core library:** `src/lib.mjs` — CLI command dispatch
|
||||||
|
- **Lock operations:** `src/lock-ops.mjs` — Nostr relay publish/query with health tracking
|
||||||
|
- **Dashboard:** `dashboard/` — Static web UI served by `src/dashboard.mjs`
|
||||||
|
- **Memory subsystem:** `src/services/memory/` — Event ingestion, retrieval, pruning
|
||||||
|
- **Scheduler:** `scripts/agent/run-scheduler-cycle.mjs` — Orchestrates agent runs
|
||||||
|
|
||||||
|
For detailed architecture docs, see `docs/lib-overview.md` and `docs/lock-ops-overview.md`.
|
||||||
|
|
||||||
|
## Test Integrity
|
||||||
|
|
||||||
|
When modifying tests, follow the test integrity protocol in `CLAUDE.md`. Tests are behavioral specifications — never weaken assertions to make them pass.
|
||||||
|
|
||||||
## Pull Requests
|
## Pull Requests
|
||||||
|
|
||||||
Please follow the repository conventions for Pull Requests.
|
- Keep PR titles short (under 70 characters)
|
||||||
|
- Include a summary of changes and test plan in the description
|
||||||
> **Note:** Detailed agent policies and conventions are normally documented in `AGENTS.md`. If this file is missing, please refer to existing patterns in the codebase or open an issue for clarification.
|
- Ensure `npm run lint` and `npm test` pass before submitting
|
||||||
|
- Reference related issues where applicable
|
||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
||||||
If you encounter any bugs or have feature requests, please open an issue on GitHub.
|
If you encounter bugs or have feature requests, please open an issue on GitHub.
|
||||||
+3
-5
@@ -1,5 +1,6 @@
|
|||||||
|
/* global marked */
|
||||||
import { KIND_APP_DATA } from '../src/constants.mjs';
|
import { KIND_APP_DATA } from '../src/constants.mjs';
|
||||||
import { createElement, escapeHtml } from './domUtils.js';
|
import { createElement } from './domUtils.js';
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// Modal Logic
|
// Modal Logic
|
||||||
@@ -168,7 +169,7 @@ function parseDashboardConfig(torchConfig = {}) {
|
|||||||
let localPrefs = {};
|
let localPrefs = {};
|
||||||
try {
|
try {
|
||||||
localPrefs = JSON.parse(localStorage.getItem('torch_dashboard_prefs')) || {};
|
localPrefs = JSON.parse(localStorage.getItem('torch_dashboard_prefs')) || {};
|
||||||
} catch {}
|
} catch { /* ignore malformed localStorage */ }
|
||||||
|
|
||||||
const dashboardConfig = torchConfig.dashboard || {};
|
const dashboardConfig = torchConfig.dashboard || {};
|
||||||
const lockConfig = torchConfig.nostrLock || {};
|
const lockConfig = torchConfig.nostrLock || {};
|
||||||
@@ -218,8 +219,6 @@ function parseDashboardConfig(torchConfig = {}) {
|
|||||||
let DASHBOARD_CONFIG = parseDashboardConfig({});
|
let DASHBOARD_CONFIG = parseDashboardConfig({});
|
||||||
|
|
||||||
let RELAYS = DASHBOARD_CONFIG.relays;
|
let RELAYS = DASHBOARD_CONFIG.relays;
|
||||||
let D_TAG_PREFIX = `${DASHBOARD_CONFIG.namespace}-lock/`;
|
|
||||||
|
|
||||||
const LOCK_EVENT_KIND = KIND_APP_DATA;
|
const LOCK_EVENT_KIND = KIND_APP_DATA;
|
||||||
let HASHTAG = DASHBOARD_CONFIG.hashtag;
|
let HASHTAG = DASHBOARD_CONFIG.hashtag;
|
||||||
|
|
||||||
@@ -787,7 +786,6 @@ async function bootstrap() {
|
|||||||
const torchConfig = await loadTorchConfigFile();
|
const torchConfig = await loadTorchConfigFile();
|
||||||
DASHBOARD_CONFIG = parseDashboardConfig(torchConfig);
|
DASHBOARD_CONFIG = parseDashboardConfig(torchConfig);
|
||||||
RELAYS = DASHBOARD_CONFIG.relays;
|
RELAYS = DASHBOARD_CONFIG.relays;
|
||||||
D_TAG_PREFIX = `${DASHBOARD_CONFIG.namespace}-lock/`;
|
|
||||||
HASHTAG = DASHBOARD_CONFIG.hashtag;
|
HASHTAG = DASHBOARD_CONFIG.hashtag;
|
||||||
|
|
||||||
cadenceFilter.value = DASHBOARD_CONFIG.defaultCadenceView;
|
cadenceFilter.value = DASHBOARD_CONFIG.defaultCadenceView;
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# TORCH System Architecture
|
||||||
|
|
||||||
|
## High-Level Overview
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TB
|
||||||
|
subgraph Agents["AI Agent Platforms"]
|
||||||
|
Jules["Jules"]
|
||||||
|
Claude["Claude Code"]
|
||||||
|
Codex["Codex"]
|
||||||
|
Goose["Goose"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph TORCH["TORCH CLI / Scheduler"]
|
||||||
|
CLI["bin/torch-lock.mjs"]
|
||||||
|
Lib["src/lib.mjs<br/>Command Dispatch"]
|
||||||
|
LockOps["src/lock-ops.mjs<br/>Lock Publisher / Query"]
|
||||||
|
Health["src/relay-health.mjs<br/>Relay Health Monitor"]
|
||||||
|
Scheduler["scripts/agent/<br/>run-scheduler-cycle.mjs"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Nostr["Nostr Network"]
|
||||||
|
R1["Relay 1<br/>relay.damus.io"]
|
||||||
|
R2["Relay 2<br/>nos.lol"]
|
||||||
|
R3["Relay 3<br/>relay.primal.net"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Dashboard["Dashboard"]
|
||||||
|
Server["src/dashboard.mjs<br/>HTTP Server"]
|
||||||
|
UI["dashboard/index.html<br/>+ app.js"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Memory["Memory Subsystem"]
|
||||||
|
Ingestor["Ingestor"]
|
||||||
|
Retriever["Retriever"]
|
||||||
|
Pruner["Pruner"]
|
||||||
|
Store["memory-store.json"]
|
||||||
|
end
|
||||||
|
|
||||||
|
Agents -->|"torch-lock lock/check/complete"| CLI
|
||||||
|
CLI --> Lib
|
||||||
|
Lib --> LockOps
|
||||||
|
LockOps -->|"NIP-01 Events<br/>(kind 30078)"| R1 & R2 & R3
|
||||||
|
Health -->|"Probe & Track"| R1 & R2 & R3
|
||||||
|
Scheduler -->|"Orchestrate"| CLI
|
||||||
|
|
||||||
|
Server -->|"Serve Static"| UI
|
||||||
|
UI -->|"WebSocket SUB"| R1 & R2 & R3
|
||||||
|
|
||||||
|
Lib --> Ingestor
|
||||||
|
Lib --> Retriever
|
||||||
|
Ingestor --> Store
|
||||||
|
Retriever --> Store
|
||||||
|
Pruner --> Store
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lock Lifecycle
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant Agent
|
||||||
|
participant TORCH as TORCH CLI
|
||||||
|
participant Relays as Nostr Relays
|
||||||
|
|
||||||
|
Agent->>TORCH: torch-lock check --cadence daily
|
||||||
|
TORCH->>Relays: Query active locks (REQ filter)
|
||||||
|
Relays-->>TORCH: Existing lock events
|
||||||
|
TORCH-->>Agent: Status: available / locked
|
||||||
|
|
||||||
|
Agent->>TORCH: torch-lock lock --agent my-agent
|
||||||
|
TORCH->>TORCH: Generate NIP-01 event (kind 30078)
|
||||||
|
TORCH->>Relays: Publish lock event (fanout)
|
||||||
|
Relays-->>TORCH: ACK from N relays
|
||||||
|
TORCH->>Relays: Race-check query (verify no conflicts)
|
||||||
|
Relays-->>TORCH: Confirm lock acquired
|
||||||
|
TORCH-->>Agent: Lock acquired (exit 0)
|
||||||
|
|
||||||
|
Note over Agent: Agent performs work...
|
||||||
|
|
||||||
|
Agent->>TORCH: torch-lock complete --agent my-agent
|
||||||
|
TORCH->>Relays: Publish completion event
|
||||||
|
TORCH-->>Agent: Completed (exit 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scheduler Flow
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
Start["Scheduler Cycle Start"] --> LoadRoster["Load Roster<br/>(roster.json)"]
|
||||||
|
LoadRoster --> Filter["Filter by cadence<br/>(daily/weekly)"]
|
||||||
|
Filter --> CheckPaused{"Agent<br/>paused?"}
|
||||||
|
CheckPaused -->|Yes| Skip["Skip agent"]
|
||||||
|
CheckPaused -->|No| CheckCompleted{"Already<br/>completed<br/>today?"}
|
||||||
|
CheckCompleted -->|Yes| Skip
|
||||||
|
CheckCompleted -->|No| CheckLock{"Lock<br/>available?"}
|
||||||
|
CheckLock -->|No| Skip
|
||||||
|
CheckLock -->|Yes| Acquire["Acquire Lock"]
|
||||||
|
Acquire --> RunAgent["Execute Agent Prompt"]
|
||||||
|
RunAgent --> Complete["Publish Completion"]
|
||||||
|
Complete --> LogResult["Write Task Log"]
|
||||||
|
Skip --> LogResult
|
||||||
|
LogResult --> Next{"More<br/>agents?"}
|
||||||
|
Next -->|Yes| CheckPaused
|
||||||
|
Next -->|No| End["Cycle Complete"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory Subsystem
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Events["Runtime Events"] --> Ingestor
|
||||||
|
Ingestor --> |"Chunk + Summarize"| Store["Memory Store<br/>(JSON file)"]
|
||||||
|
Store --> Retriever
|
||||||
|
Retriever --> |"Rank: semantic +<br/>importance + recency"| Results["Ranked Memories"]
|
||||||
|
|
||||||
|
Scheduler["Maintenance<br/>Scheduler"] --> Pruner
|
||||||
|
Pruner --> |"TTL / merge /<br/>archive / delete"| Store
|
||||||
|
|
||||||
|
subgraph Jobs["Scheduled Jobs"]
|
||||||
|
J1["Ingest (1-5 min)"]
|
||||||
|
J2["Consolidate (1 hr)"]
|
||||||
|
J3["Prune (daily)"]
|
||||||
|
J4["Deep Merge (weekly)"]
|
||||||
|
end
|
||||||
|
Scheduler --> Jobs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Data Flows
|
||||||
|
|
||||||
|
| Flow | Protocol | Event Kind | Key Fields |
|
||||||
|
|------|----------|-----------|------------|
|
||||||
|
| Lock acquire | NIP-01 publish | 30078 | d-tag, expiration, agent, cadence, status |
|
||||||
|
| Lock query | NIP-01 REQ | 30078 | #t filter on hashtag |
|
||||||
|
| Lock complete | NIP-01 publish | 30078 | status: "completed" |
|
||||||
|
| Dashboard feed | NIP-01 WebSocket | 30078 | Real-time SUB with since filter |
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
TORCH/
|
||||||
|
├── bin/ # CLI entry point
|
||||||
|
├── src/
|
||||||
|
│ ├── lib.mjs # Command dispatch
|
||||||
|
│ ├── lock-ops.mjs # Nostr relay operations
|
||||||
|
│ ├── relay-health.mjs # Relay health monitoring
|
||||||
|
│ ├── dashboard.mjs # Dashboard HTTP server
|
||||||
|
│ ├── ops.mjs # Install/update operations
|
||||||
|
│ ├── services/
|
||||||
|
│ │ ├── memory/ # Memory subsystem
|
||||||
|
│ │ └── governance/ # Governance service
|
||||||
|
│ └── prompts/ # Agent prompt definitions
|
||||||
|
├── dashboard/ # Dashboard frontend
|
||||||
|
├── scripts/agent/ # Scheduler and agent scripts
|
||||||
|
├── test/ # Test suite
|
||||||
|
├── docs/ # Architecture documentation
|
||||||
|
└── migrations/ # Database schemas (future)
|
||||||
|
```
|
||||||
+1
-1
@@ -16,7 +16,7 @@ export default [
|
|||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"no-unused-vars": "warn",
|
"no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" }],
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
-64
@@ -17,7 +17,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@playwright/test": "^1.58.2",
|
|
||||||
"eslint": "^10.0.0",
|
"eslint": "^10.0.0",
|
||||||
"globals": "^17.3.0"
|
"globals": "^17.3.0"
|
||||||
},
|
},
|
||||||
@@ -260,22 +259,6 @@
|
|||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"playwright": "1.58.2"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@scure/base": {
|
"node_modules/@scure/base": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
|
||||||
@@ -691,21 +674,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/fsevents": {
|
|
||||||
"version": "2.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
|
||||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob-parent": {
|
"node_modules/glob-parent": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
||||||
@@ -988,38 +956,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"playwright-core": "1.58.2"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"playwright": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"fsevents": "2.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/playwright-core": {
|
|
||||||
"version": "1.58.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
|
|
||||||
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"playwright-core": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { createLifecyclePlan } from '../src/services/memory/pruner.js';
|
import { createLifecyclePlan } from '../src/services/memory/pruner.js';
|
||||||
import crypto from 'node:crypto';
|
|
||||||
|
|
||||||
const COUNT = 30000;
|
const COUNT = 30000;
|
||||||
const DUPLICATE_WINDOW_MS = 1000 * 60 * 60; // 1 hour
|
const DUPLICATE_WINDOW_MS = 1000 * 60 * 60; // 1 hour
|
||||||
|
|||||||
@@ -16,11 +16,8 @@ const getArg = (key) => {
|
|||||||
if (flagIdx !== -1 && ARGS[flagIdx + 1] && !ARGS[flagIdx + 1].startsWith('--')) return ARGS[flagIdx + 1];
|
if (flagIdx !== -1 && ARGS[flagIdx + 1] && !ARGS[flagIdx + 1].startsWith('--')) return ARGS[flagIdx + 1];
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
const hasArg = (key) => ARGS.includes(`--${key}`);
|
|
||||||
|
|
||||||
const RELAYS = (getArg('relays') || process.env.RELAY_URLS || '').split(',').filter(Boolean);
|
const RELAYS = (getArg('relays') || process.env.RELAY_URLS || '').split(',').filter(Boolean);
|
||||||
const SERVE_CMD = getArg('serve') || 'npx';
|
const SERVE_CMD = getArg('serve') || 'npx';
|
||||||
const CONFIRM_PUBLIC = hasArg('confirm-public');
|
|
||||||
const OUT_DIR = getArg('out') || 'artifacts';
|
const OUT_DIR = getArg('out') || 'artifacts';
|
||||||
|
|
||||||
// --- Logging ---
|
// --- Logging ---
|
||||||
@@ -45,7 +42,7 @@ async function waitForServer(url, timeoutMs = 10000) {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (res.ok) return true;
|
if (res.ok) return true;
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
await sleep(500);
|
await sleep(500);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async function waitForServer() {
|
|||||||
req.end();
|
req.end();
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
await sleep(100);
|
await sleep(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,8 +59,8 @@ async function benchmark() {
|
|||||||
if (current >= REQUESTS) break;
|
if (current >= REQUESTS) break;
|
||||||
try {
|
try {
|
||||||
await makeRequest();
|
await makeRequest();
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// console.error(e);
|
// console.error(_e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ async function runBenchmark() {
|
|||||||
duplicateWindowMs: 1000 * 60 * 60, // 1 hour
|
duplicateWindowMs: 1000 * 60 * 60, // 1 hour
|
||||||
similarityThreshold: 0.99,
|
similarityThreshold: 0.99,
|
||||||
getEmbedding: getEmbeddingWrapper,
|
getEmbedding: getEmbeddingWrapper,
|
||||||
generateSummary: async (prompt) => {
|
generateSummary: async (_prompt) => {
|
||||||
await delay(LATENCY_MS);
|
await delay(LATENCY_MS);
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
summary: 'Condensed summary based on prompt.',
|
summary: 'Condensed summary based on prompt.',
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ async function runTests(i) {
|
|||||||
|
|
||||||
child.stdout.on('data', (d) => stdout += d.toString());
|
child.stdout.on('data', (d) => stdout += d.toString());
|
||||||
|
|
||||||
child.on('close', (code) => {
|
child.on('close', (_code) => {
|
||||||
const lines = stdout.split('\n');
|
const lines = stdout.split('\n');
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (line.startsWith('not ok ') && !line.includes('# skip') && !line.includes('# todo')) {
|
if (line.startsWith('not ok ') && !line.includes('# skip') && !line.includes('# todo')) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function getFiles(dir, files = []) {
|
|||||||
files.push(name);
|
files.push(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// ignore if dir doesn't exist
|
// ignore if dir doesn't exist
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { createProposal, listProposals, applyProposal, rejectProposal, getProposal } from './services/governance/index.js';
|
import { createProposal, listProposals, applyProposal, rejectProposal, getProposal } from './services/governance/index.js';
|
||||||
import { ExitError } from './errors.mjs';
|
import { ExitError } from './errors.mjs';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
|
||||||
|
|
||||||
export async function cmdProposal(subcommand, args = {}) {
|
export async function cmdProposal(subcommand, args = {}) {
|
||||||
switch (subcommand) {
|
switch (subcommand) {
|
||||||
@@ -30,7 +29,7 @@ async function handleCreate({ agent, target, contentFile, reason }) {
|
|||||||
let newContent;
|
let newContent;
|
||||||
try {
|
try {
|
||||||
newContent = await fs.readFile(contentFile, 'utf8');
|
newContent = await fs.readFile(contentFile, 'utf8');
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
console.error(`Failed to read content file: ${contentFile}`);
|
console.error(`Failed to read content file: ${contentFile}`);
|
||||||
throw new ExitError(1, 'File read error');
|
throw new ExitError(1, 'File read error');
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-11
@@ -9,19 +9,13 @@ import {
|
|||||||
} from './torch-config.mjs';
|
} from './torch-config.mjs';
|
||||||
import {
|
import {
|
||||||
KIND_APP_DATA,
|
KIND_APP_DATA,
|
||||||
DEFAULT_RETRY_ATTEMPTS,
|
|
||||||
DEFAULT_RETRY_BASE_DELAY_MS,
|
|
||||||
DEFAULT_RETRY_CAP_DELAY_MS,
|
|
||||||
DEFAULT_ROLLING_WINDOW_SIZE,
|
DEFAULT_ROLLING_WINDOW_SIZE,
|
||||||
DEFAULT_FAILURE_THRESHOLD,
|
DEFAULT_FAILURE_THRESHOLD,
|
||||||
DEFAULT_QUARANTINE_COOLDOWN_MS,
|
DEFAULT_QUARANTINE_COOLDOWN_MS,
|
||||||
DEFAULT_MAX_QUARANTINE_COOLDOWN_MS,
|
DEFAULT_MAX_QUARANTINE_COOLDOWN_MS,
|
||||||
DEFAULT_SNAPSHOT_INTERVAL_MS,
|
DEFAULT_SNAPSHOT_INTERVAL_MS,
|
||||||
} from './constants.mjs';
|
} from './constants.mjs';
|
||||||
|
import { nowUnix } from './utils.mjs';
|
||||||
function nowUnix() {
|
|
||||||
return Math.floor(Date.now() / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a raw Nostr event into a structured lock object.
|
* Parses a raw Nostr event into a structured lock object.
|
||||||
@@ -630,10 +624,6 @@ export class LockPublisher {
|
|||||||
async publish() {
|
async publish() {
|
||||||
const {
|
const {
|
||||||
poolFactory = () => new SimplePool(),
|
poolFactory = () => new SimplePool(),
|
||||||
getPublishTimeoutMsFn = getPublishTimeoutMs,
|
|
||||||
getMinSuccessfulRelayPublishesFn = getMinSuccessfulRelayPublishes,
|
|
||||||
getRelayFallbacksFn = getRelayFallbacks,
|
|
||||||
getMinActiveRelayPoolFn = getMinActiveRelayPool,
|
|
||||||
retryAttempts = 4,
|
retryAttempts = 4,
|
||||||
retryBaseDelayMs = 500,
|
retryBaseDelayMs = 500,
|
||||||
retryCapDelayMs = 8_000,
|
retryCapDelayMs = 8_000,
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ export async function getCompletedAgents(cadence, logDir, deps) {
|
|||||||
const match = file.match(/^(\d{4}-\d{2}-\d{2})T.*__([a-zA-Z0-9-_]+)__(.*)\.md$/);
|
const match = file.match(/^(\d{4}-\d{2}-\d{2})T.*__([a-zA-Z0-9-_]+)__(.*)\.md$/);
|
||||||
if (!match) continue;
|
if (!match) continue;
|
||||||
|
|
||||||
const [_, datePart, agent, status] = match;
|
const [, datePart, agent, status] = match;
|
||||||
|
|
||||||
if (status === 'completed') {
|
if (status === 'completed') {
|
||||||
if (cadence === 'daily' && datePart === today) {
|
if (cadence === 'daily' && datePart === today) {
|
||||||
|
|||||||
+1
-1
@@ -381,7 +381,7 @@ export function cmdUpdate(force = false, cwd = process.cwd()) {
|
|||||||
if (pkg.name === 'torch-lock') {
|
if (pkg.name === 'torch-lock') {
|
||||||
installDirName = '.';
|
installDirName = '.';
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// Ignore error if package.json is missing or invalid
|
// Ignore error if package.json is missing or invalid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ async function run() {
|
|||||||
const res = await loadTorchConfig();
|
const res = await loadTorchConfig();
|
||||||
// Use res to prevent dead code elimination if JIT is smart (though side effects exist)
|
// Use res to prevent dead code elimination if JIT is smart (though side effects exist)
|
||||||
if (!res) throw new Error("Failed");
|
if (!res) throw new Error("Failed");
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export async function listProposals() {
|
|||||||
id: entry.name,
|
id: entry.name,
|
||||||
...meta
|
...meta
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// Ignore invalid proposals
|
// Ignore invalid proposals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ export async function createProposal({ agent, target, newContent, reason }) {
|
|||||||
console.error('Diff generation failed:', e.message);
|
console.error('Diff generation failed:', e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
diff = '(New File)';
|
diff = '(New File)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ export async function applyProposal(id) {
|
|||||||
// User requested <path>/<hash>.md.
|
// User requested <path>/<hash>.md.
|
||||||
const archivePath = path.join(archiveDir, `${path.basename(meta.target, '.md')}_${hash}.md`);
|
const archivePath = path.join(archiveDir, `${path.basename(meta.target, '.md')}_${hash}.md`);
|
||||||
await fs.writeFile(archivePath, oldContent);
|
await fs.writeFile(archivePath, oldContent);
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// If file didn't exist, nothing to archive
|
// If file didn't exist, nothing to archive
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ export async function rollbackPrompt(target, hashOrStrategy = 'latest') {
|
|||||||
sourceContent = await fs.readFile(path.join(archiveDir, match), 'utf8');
|
sourceContent = await fs.readFile(path.join(archiveDir, match), 'utf8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// Archive lookup failed
|
// Archive lookup failed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const VECTOR_BACKEND_ENV = 'MEMORY_VECTOR_BACKEND';
|
|||||||
* @param {string} text
|
* @param {string} text
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
function fallbackEmbedding(text) {
|
function fallbackEmbedding(_text) {
|
||||||
// Disabled as per configuration: Jules uses text-based memory, not vector embeddings.
|
// Disabled as per configuration: Jules uses text-based memory, not vector embeddings.
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { getMemoryPruneMode, isMemoryIngestEnabled } from './feature-flags.js';
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import util from 'node:util';
|
import util from 'node:util';
|
||||||
import { ensureDir } from '../../utils.mjs';
|
|
||||||
|
|
||||||
const MEMORY_FILE_PATH = path.join(process.cwd(), '.scheduler-memory', 'memory-store.json');
|
const MEMORY_FILE_PATH = path.join(process.cwd(), '.scheduler-memory', 'memory-store.json');
|
||||||
const debug = util.debuglog('torch-memory');
|
const debug = util.debuglog('torch-memory');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test, describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { cmdList } from '../src/cmd-list.mjs';
|
import { cmdList } from '../src/cmd-list.mjs';
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ test('Dashboard Configuration Exposure Security', async (t) => {
|
|||||||
|
|
||||||
// Override env to use this config
|
// Override env to use this config
|
||||||
const originalEnvPath = process.env.TORCH_CONFIG_PATH;
|
const originalEnvPath = process.env.TORCH_CONFIG_PATH;
|
||||||
const originalAuth = process.env.TORCH_DASHBOARD_AUTH;
|
|
||||||
|
|
||||||
process.env.TORCH_CONFIG_PATH = tempConfigPath;
|
process.env.TORCH_CONFIG_PATH = tempConfigPath;
|
||||||
// Disable auth via env so we can access the endpoint without credentials
|
// Disable auth via env so we can access the endpoint without credentials
|
||||||
// The vulnerability is about exposure of *other* fields.
|
// The vulnerability is about exposure of *other* fields.
|
||||||
@@ -93,7 +91,7 @@ test('Dashboard Configuration Exposure Security', async (t) => {
|
|||||||
let exposedConfig;
|
let exposedConfig;
|
||||||
try {
|
try {
|
||||||
exposedConfig = JSON.parse(responseBody);
|
exposedConfig = JSON.parse(responseBody);
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
assert.fail(`Failed to parse JSON response: ${responseBody}`);
|
assert.fail(`Failed to parse JSON response: ${responseBody}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ describe('src/lib.mjs', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('cmdLock', () => {
|
describe('cmdLock', () => {
|
||||||
const mockPublishLock = async () => {};
|
|
||||||
const mockGenerateSecretKey = () => new Uint8Array(32);
|
const mockGenerateSecretKey = () => new Uint8Array(32);
|
||||||
const mockGetPublicKey = () => 'mock-pubkey';
|
const mockGetPublicKey = () => 'mock-pubkey';
|
||||||
const mockFinalizeEvent = (t) => ({ ...t, id: 'mock-id', sig: 'mock-sig' });
|
const mockFinalizeEvent = (t) => ({ ...t, id: 'mock-id', sig: 'mock-sig' });
|
||||||
@@ -353,7 +352,6 @@ describe('src/lib.mjs', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('cmdComplete', () => {
|
describe('cmdComplete', () => {
|
||||||
const mockPublishLock = async () => {};
|
|
||||||
const mockGenerateSecretKey = () => new Uint8Array(32);
|
const mockGenerateSecretKey = () => new Uint8Array(32);
|
||||||
const mockGetPublicKey = () => 'mock-pubkey';
|
const mockGetPublicKey = () => 'mock-pubkey';
|
||||||
const mockFinalizeEvent = (t) => ({ ...t, id: 'mock-id-complete' });
|
const mockFinalizeEvent = (t) => ({ ...t, id: 'mock-id-complete' });
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ test('runPruneCycle respects prune feature-flag modes', async () => {
|
|||||||
test('markMemoryMerged delegates to repository and clears cache', async () => {
|
test('markMemoryMerged delegates to repository and clears cache', async () => {
|
||||||
let callCount = 0;
|
let callCount = 0;
|
||||||
const repository = {
|
const repository = {
|
||||||
async markMerged(id, mergedInto) {
|
async markMerged(id, _mergedInto) {
|
||||||
callCount++;
|
callCount++;
|
||||||
return id === 'exists';
|
return id === 'exists';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
formatMemoryBlock,
|
formatMemoryBlock,
|
||||||
formatMemoriesForPrompt,
|
formatMemoriesForPrompt,
|
||||||
renderPromptWithMemoryContext,
|
renderPromptWithMemoryContext,
|
||||||
isMemoryRetrievalEnabled
|
|
||||||
} from '../src/services/memory/formatter.js';
|
} from '../src/services/memory/formatter.js';
|
||||||
|
|
||||||
function createMemory(overrides = {}) {
|
function createMemory(overrides = {}) {
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ test('getRelevantMemories passes correct parameters to ranker', async (t) => {
|
|||||||
await getRelevantMemories(params);
|
await getRelevantMemories(params);
|
||||||
|
|
||||||
assert.equal(ranker.mock.callCount(), 1);
|
assert.equal(ranker.mock.callCount(), 1);
|
||||||
const [_, queryParams] = ranker.mock.calls[0].arguments;
|
const [, queryParams] = ranker.mock.calls[0].arguments;
|
||||||
|
|
||||||
assert.equal(queryParams.agent_id, 'agent-1');
|
assert.equal(queryParams.agent_id, 'agent-1');
|
||||||
assert.equal(queryParams.query, 'my query');
|
assert.equal(queryParams.query, 'my query');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test, describe, beforeEach, afterEach } from 'node:test';
|
import { test, describe, beforeEach } from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { ingestEvents, getRelevantMemories } from '../src/services/memory/index.js';
|
import { ingestEvents, getRelevantMemories } from '../src/services/memory/index.js';
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ describe('ingestEvents', () => {
|
|||||||
let linkedEmbeddings = new Map();
|
let linkedEmbeddings = new Map();
|
||||||
|
|
||||||
const mockOptions = {
|
const mockOptions = {
|
||||||
embedText: async (text) => Array(128).fill(0.1), // Deterministic embedding
|
embedText: async (_text) => Array(128).fill(0.1), // Deterministic embedding
|
||||||
emitTelemetry: (event, payload) => telemetryEvents.push({ event, payload }),
|
emitTelemetry: (event, payload) => telemetryEvents.push({ event, payload }),
|
||||||
metrics: {
|
metrics: {
|
||||||
emit: (metric, payload) => metricsEvents.push({ metric, payload }),
|
emit: (metric, payload) => metricsEvents.push({ metric, payload }),
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ test('pinMemory returns null for non-existent ID but still clears cache', async
|
|||||||
listMemoriesCallCount++;
|
listMemoriesCallCount++;
|
||||||
return records;
|
return records;
|
||||||
},
|
},
|
||||||
async setPinned(id, pinned) {
|
async setPinned(_id, _pinned) {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
async updateMemoryUsage() { return null; }
|
async updateMemoryUsage() { return null; }
|
||||||
@@ -121,7 +121,7 @@ test('unpinMemory returns null for non-existent ID but still clears cache', asyn
|
|||||||
listMemoriesCallCount++;
|
listMemoriesCallCount++;
|
||||||
return records;
|
return records;
|
||||||
},
|
},
|
||||||
async setPinned(id, pinned) {
|
async setPinned(_id, _pinned) {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
async updateMemoryUsage() { return null; }
|
async updateMemoryUsage() { return null; }
|
||||||
|
|||||||
@@ -42,8 +42,7 @@ test.before(async () => {
|
|||||||
await fs.mkdir(memDir, { recursive: true });
|
await fs.mkdir(memDir, { recursive: true });
|
||||||
|
|
||||||
// Create initial state
|
// Create initial state
|
||||||
const now = 200_000;
|
// now = 200_000, retentionMs will be 100,000
|
||||||
// retentionMs will be 100,000
|
|
||||||
// cutoff = 100,000
|
// cutoff = 100,000
|
||||||
|
|
||||||
const memories = [
|
const memories = [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { test, describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
import assert from 'node:assert';
|
import assert from 'node:assert';
|
||||||
import { spawnSync } from 'node:child_process';
|
import { spawnSync } from 'node:child_process';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
|||||||
Reference in new issue
Block a user