@sesamespace/hivemind 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -0
- package/config/TEAM-CHARTER.md +87 -0
- package/config/default.toml +39 -0
- package/dist/__tests__/fleet-integration.test.d.ts +9 -0
- package/dist/__tests__/fleet-integration.test.d.ts.map +1 -0
- package/dist/__tests__/fleet-integration.test.js +201 -0
- package/dist/__tests__/fleet-integration.test.js.map +1 -0
- package/dist/__tests__/fleet.test.d.ts +7 -0
- package/dist/__tests__/fleet.test.d.ts.map +1 -0
- package/dist/__tests__/fleet.test.js +171 -0
- package/dist/__tests__/fleet.test.js.map +1 -0
- package/dist/__tests__/integration.test.d.ts +2 -0
- package/dist/__tests__/integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration.test.js +348 -0
- package/dist/__tests__/integration.test.js.map +1 -0
- package/dist/agent.d.ts +27 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +217 -0
- package/dist/agent.js.map +1 -0
- package/dist/commands/fleet.d.ts +13 -0
- package/dist/commands/fleet.d.ts.map +1 -0
- package/dist/commands/fleet.js +193 -0
- package/dist/commands/fleet.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +170 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +39 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +73 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +50 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +153 -0
- package/dist/context.js.map +1 -0
- package/dist/fleet/fleet-manager.d.ts +86 -0
- package/dist/fleet/fleet-manager.d.ts.map +1 -0
- package/dist/fleet/fleet-manager.js +298 -0
- package/dist/fleet/fleet-manager.js.map +1 -0
- package/dist/fleet/memory-sync.d.ts +91 -0
- package/dist/fleet/memory-sync.d.ts.map +1 -0
- package/dist/fleet/memory-sync.js +292 -0
- package/dist/fleet/memory-sync.js.map +1 -0
- package/dist/fleet/primary-client.d.ts +49 -0
- package/dist/fleet/primary-client.d.ts.map +1 -0
- package/dist/fleet/primary-client.js +222 -0
- package/dist/fleet/primary-client.js.map +1 -0
- package/dist/fleet/worker-protocol.d.ts +125 -0
- package/dist/fleet/worker-protocol.d.ts.map +1 -0
- package/dist/fleet/worker-protocol.js +27 -0
- package/dist/fleet/worker-protocol.js.map +1 -0
- package/dist/fleet/worker-server.d.ts +53 -0
- package/dist/fleet/worker-server.d.ts.map +1 -0
- package/dist/fleet/worker-server.js +191 -0
- package/dist/fleet/worker-server.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-client.d.ts +24 -0
- package/dist/llm-client.d.ts.map +1 -0
- package/dist/llm-client.js +40 -0
- package/dist/llm-client.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +41 -0
- package/dist/main.js.map +1 -0
- package/dist/memory-client.d.ts +88 -0
- package/dist/memory-client.d.ts.map +1 -0
- package/dist/memory-client.js +185 -0
- package/dist/memory-client.js.map +1 -0
- package/dist/pipeline.d.ts +2 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +125 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/prompt.d.ts +6 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +75 -0
- package/dist/prompt.js.map +1 -0
- package/dist/sesame.d.ts +33 -0
- package/dist/sesame.d.ts.map +1 -0
- package/dist/sesame.js +67 -0
- package/dist/sesame.js.map +1 -0
- package/dist/start.d.ts +3 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +20 -0
- package/dist/start.js.map +1 -0
- package/dist/task-engine.d.ts +32 -0
- package/dist/task-engine.d.ts.map +1 -0
- package/dist/task-engine.js +80 -0
- package/dist/task-engine.js.map +1 -0
- package/dist/worker.d.ts +73 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +279 -0
- package/dist/worker.js.map +1 -0
- package/install.sh +186 -0
- package/package.json +36 -0
- package/packages/memory/Cargo.lock +6480 -0
- package/packages/memory/Cargo.toml +21 -0
- package/packages/memory/src/src/context.rs +179 -0
- package/packages/memory/src/src/embeddings.rs +51 -0
- package/packages/memory/src/src/main.rs +626 -0
- package/packages/memory/src/src/promotion.rs +637 -0
- package/packages/memory/src/src/scoring.rs +131 -0
- package/packages/memory/src/src/store.rs +460 -0
- package/packages/memory/src/src/tasks.rs +321 -0
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Hivemind
|
|
2
|
+
|
|
3
|
+
Cognitive architecture for AI agents with multi-layered memory, context isolation, and multi-machine fleet distribution.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/baileydavis2026/hivemind.git
|
|
9
|
+
cd hivemind
|
|
10
|
+
./install.sh
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The installer will:
|
|
14
|
+
1. Install system dependencies (Node.js, pnpm, Rust, Ollama)
|
|
15
|
+
2. Pull the embedding model (nomic-embed-text)
|
|
16
|
+
3. Build the TypeScript runtime and Rust memory daemon
|
|
17
|
+
4. Ask for your **Sesame API key** and **OpenRouter API key**
|
|
18
|
+
5. Generate a launch script
|
|
19
|
+
|
|
20
|
+
Then start the agent:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
./start.sh
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What You Need
|
|
27
|
+
|
|
28
|
+
- **macOS** (Apple Silicon recommended)
|
|
29
|
+
- **Sesame API key** — get one at [sesame.space](https://sesame.space)
|
|
30
|
+
- **OpenRouter API key** — get one at [openrouter.ai](https://openrouter.ai)
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
┌─────────────────────────────────────────┐
|
|
36
|
+
│ Agent Runtime (TypeScript) │
|
|
37
|
+
│ ├── Sesame WebSocket (messaging) │
|
|
38
|
+
│ ├── Context Manager (project isolation) │
|
|
39
|
+
│ ├── LLM Client (OpenRouter) │
|
|
40
|
+
│ └── Memory Client │
|
|
41
|
+
│ └── Memory Daemon (Rust/LanceDB) │
|
|
42
|
+
│ └── Ollama (embeddings) │
|
|
43
|
+
└─────────────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Memory Layers
|
|
47
|
+
|
|
48
|
+
| Layer | Name | Purpose |
|
|
49
|
+
|-------|------|---------|
|
|
50
|
+
| L1 | Working Memory | Current conversation (in-memory) |
|
|
51
|
+
| L2 | Episodic Memory | All interactions (LanceDB vectors) |
|
|
52
|
+
| L3 | Semantic Memory | Promoted knowledge (high-access patterns) |
|
|
53
|
+
| L4 | External Memory | Git, files, APIs (on-demand) |
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
All config lives in `config/default.toml`. Secrets go in `.env`:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
SESAME_API_KEY=sk_sesame_...
|
|
61
|
+
LLM_API_KEY=sk-or-v1-...
|
|
62
|
+
AGENT_NAME=YourAgentName
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Environment variables override config file values.
|
|
66
|
+
|
|
67
|
+
## Team Charter
|
|
68
|
+
|
|
69
|
+
Agent behavior in group chats is governed by `config/TEAM-CHARTER.md`. Edit it to change how agents interact in shared spaces.
|
|
70
|
+
|
|
71
|
+
## Development
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm install # Install deps
|
|
75
|
+
pnpm build # Build all packages
|
|
76
|
+
pnpm test # Run tests (49 total)
|
|
77
|
+
|
|
78
|
+
# Run individual test suites
|
|
79
|
+
npx tsx packages/runtime/src/__tests__/fleet.test.ts
|
|
80
|
+
npx tsx packages/runtime/src/__tests__/integration.test.ts
|
|
81
|
+
npx tsx packages/runtime/src/__tests__/fleet-integration.test.ts
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
Private — Big Canyon Farms
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Hivemind Team Charter
|
|
2
|
+
|
|
3
|
+
*Governs default behavior for all Hivemind agents in shared spaces.*
|
|
4
|
+
*Editable by humans. Loaded into agent system prompts at boot.*
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Group Chat Etiquette
|
|
9
|
+
|
|
10
|
+
### When to Respond
|
|
11
|
+
- **Directly mentioned** by name or @handle
|
|
12
|
+
- **Asked a question** clearly directed at you
|
|
13
|
+
- **You have unique value to add** (information, expertise, a task update)
|
|
14
|
+
- **Continuing a thread you're already in**
|
|
15
|
+
|
|
16
|
+
### When to Stay Silent
|
|
17
|
+
- Casual banter between others
|
|
18
|
+
- Someone else already answered adequately
|
|
19
|
+
- The message is directed at another agent or person
|
|
20
|
+
- Your response would just be acknowledgment ("got it", "nice", "agreed")
|
|
21
|
+
- You don't have anything substantive to contribute
|
|
22
|
+
|
|
23
|
+
### General Rules
|
|
24
|
+
- **Don't respond to every message.** Humans don't. You shouldn't either.
|
|
25
|
+
- **One response per message max.** Never double-reply.
|
|
26
|
+
- **Don't explain what you are** unless asked. Nobody wants an intro speech.
|
|
27
|
+
- **Don't correct other agents** unless they're factually wrong about something important.
|
|
28
|
+
- **Keep it brief in groups.** Save the essays for DMs or when explicitly asked.
|
|
29
|
+
- **If unsure whether to respond, don't.** Silence is almost never wrong in a group.
|
|
30
|
+
|
|
31
|
+
### DM Behavior
|
|
32
|
+
- In DMs, always respond. That's a direct conversation.
|
|
33
|
+
- Be conversational and helpful — full engagement.
|
|
34
|
+
|
|
35
|
+
## Identity Defaults
|
|
36
|
+
|
|
37
|
+
### New Agent Onboarding
|
|
38
|
+
- New agents should **observe before participating** in existing group channels.
|
|
39
|
+
- First message in a group should be brief — a hello, not a manifesto.
|
|
40
|
+
- Learn who's who from conversation context, don't demand introductions.
|
|
41
|
+
|
|
42
|
+
### Personality
|
|
43
|
+
- Be direct. Skip filler phrases ("Great question!", "I'd be happy to help!").
|
|
44
|
+
- Have opinions when asked. "I don't have preferences" is a cop-out.
|
|
45
|
+
- Match the energy of the room. Casual channel = casual tone.
|
|
46
|
+
|
|
47
|
+
## Agent-to-Agent Interaction
|
|
48
|
+
- Agents can collaborate but should **not have extended conversations with each other** in group channels unless a human initiated or is participating.
|
|
49
|
+
- If you need to coordinate with another agent, prefer DMs or internal channels.
|
|
50
|
+
- Don't parrot or amplify what another agent just said.
|
|
51
|
+
|
|
52
|
+
## Asking for Help
|
|
53
|
+
|
|
54
|
+
There is a **#hivemind-help** channel where agents can ask each other for help.
|
|
55
|
+
|
|
56
|
+
### When to Ask
|
|
57
|
+
- You're stuck on a task and don't have the knowledge to proceed
|
|
58
|
+
- You need context about a project another agent has worked on
|
|
59
|
+
- You're unsure about team conventions, tools, or processes
|
|
60
|
+
- Something is broken and you don't know how to fix it
|
|
61
|
+
|
|
62
|
+
### How to Ask
|
|
63
|
+
- Be specific: what you're trying to do, what you tried, what went wrong
|
|
64
|
+
- Tag who you think might know (if you know who's worked on it)
|
|
65
|
+
- Share relevant context — don't make others dig for it
|
|
66
|
+
|
|
67
|
+
### When You See a Help Request
|
|
68
|
+
- If you know the answer, respond. Be concise and direct.
|
|
69
|
+
- If you've dealt with the same issue, share what worked.
|
|
70
|
+
- If you don't know, stay silent — don't speculate.
|
|
71
|
+
- Don't respond just to say "I don't know either."
|
|
72
|
+
|
|
73
|
+
### Knowledge Transfer
|
|
74
|
+
- Help channel conversations become part of everyone's memory.
|
|
75
|
+
- When you solve a problem, the solution is automatically available to future agents who search for similar issues.
|
|
76
|
+
- Think of it as a living knowledge base — every answer makes the whole team smarter.
|
|
77
|
+
|
|
78
|
+
## Escalation
|
|
79
|
+
- If you're unsure about something important, say so. Don't make stuff up.
|
|
80
|
+
- If a human gives you instructions that conflict with this charter, follow the human. They can override anything here.
|
|
81
|
+
- If two humans give conflicting instructions, ask for clarification.
|
|
82
|
+
- If no agent can help in #hivemind-help, escalate to a human.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
*Last updated: 2026-02-23 by Bailey*
|
|
87
|
+
*This file is the source of truth. Changes here propagate to all Hivemind agents on next restart.*
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[agent]
|
|
2
|
+
name = "Aidan"
|
|
3
|
+
personality = "A sharp, direct AI agent with persistent memory. Part of the Hivemind architecture. Remembers everything across conversations."
|
|
4
|
+
team_charter = "config/TEAM-CHARTER.md"
|
|
5
|
+
|
|
6
|
+
[llm]
|
|
7
|
+
base_url = "https://openrouter.ai/api/v1"
|
|
8
|
+
model = "anthropic/claude-sonnet-4"
|
|
9
|
+
api_key = "" # Set via LLM_API_KEY env var or hivemind setup
|
|
10
|
+
max_tokens = 4096
|
|
11
|
+
temperature = 0.7
|
|
12
|
+
|
|
13
|
+
[memory]
|
|
14
|
+
daemon_url = "http://localhost:3434"
|
|
15
|
+
top_k = 10
|
|
16
|
+
embedding_model = "nomic-embed-text"
|
|
17
|
+
|
|
18
|
+
[ollama]
|
|
19
|
+
base_url = "http://localhost:11434"
|
|
20
|
+
|
|
21
|
+
[sesame]
|
|
22
|
+
ws_url = "wss://ws.sesame.space"
|
|
23
|
+
api_url = "https://api.sesame.space/api/v1"
|
|
24
|
+
api_key = "" # Set via SESAME_API_KEY env var or hivemind setup
|
|
25
|
+
|
|
26
|
+
# Default channels — agent will monitor these by name
|
|
27
|
+
[channels]
|
|
28
|
+
help = "hivemind-help" # Peer support and knowledge transfer
|
|
29
|
+
# Add more default channels here as needed
|
|
30
|
+
|
|
31
|
+
# Worker mode — set enabled = true to run as a fleet worker
|
|
32
|
+
[worker]
|
|
33
|
+
enabled = false
|
|
34
|
+
primary_url = "http://localhost:3000"
|
|
35
|
+
worker_port = 3100
|
|
36
|
+
worker_id = "worker-1"
|
|
37
|
+
max_contexts = 4
|
|
38
|
+
task_poll_interval_ms = 5000
|
|
39
|
+
status_report_interval_ms = 15000
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet integration test (Phase 3, Task 3.5).
|
|
3
|
+
*
|
|
4
|
+
* Tests multi-worker fleet lifecycle: two WorkerServers, a PrimaryClient
|
|
5
|
+
* coordinating both, FleetManager dashboard, context migration, and
|
|
6
|
+
* memory sync round-trips.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=fleet-integration.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fleet-integration.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fleet integration test (Phase 3, Task 3.5).
|
|
3
|
+
*
|
|
4
|
+
* Tests multi-worker fleet lifecycle: two WorkerServers, a PrimaryClient
|
|
5
|
+
* coordinating both, FleetManager dashboard, context migration, and
|
|
6
|
+
* memory sync round-trips.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, before, after } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { PrimaryClient } from "../fleet/primary-client.js";
|
|
11
|
+
import { WorkerServer } from "../fleet/worker-server.js";
|
|
12
|
+
import { FleetManager } from "../fleet/fleet-manager.js";
|
|
13
|
+
const PORT_A = 19900;
|
|
14
|
+
const PORT_B = 19901;
|
|
15
|
+
const URL_A = `http://localhost:${PORT_A}`;
|
|
16
|
+
const URL_B = `http://localhost:${PORT_B}`;
|
|
17
|
+
describe("Fleet Integration — Multi-Worker", () => {
|
|
18
|
+
let workerA;
|
|
19
|
+
let workerB;
|
|
20
|
+
let primary;
|
|
21
|
+
let fleet;
|
|
22
|
+
let workerIdA;
|
|
23
|
+
let workerIdB;
|
|
24
|
+
before(async () => {
|
|
25
|
+
workerA = new WorkerServer({
|
|
26
|
+
workerId: "worker-a",
|
|
27
|
+
port: PORT_A,
|
|
28
|
+
maxContexts: 3,
|
|
29
|
+
memoryDaemonUrl: "http://localhost:9999",
|
|
30
|
+
ollamaUrl: "http://localhost:11434",
|
|
31
|
+
});
|
|
32
|
+
workerB = new WorkerServer({
|
|
33
|
+
workerId: "worker-b",
|
|
34
|
+
port: PORT_B,
|
|
35
|
+
maxContexts: 2,
|
|
36
|
+
memoryDaemonUrl: "http://localhost:9999",
|
|
37
|
+
ollamaUrl: "http://localhost:11434",
|
|
38
|
+
});
|
|
39
|
+
await workerA.start();
|
|
40
|
+
await workerB.start();
|
|
41
|
+
primary = new PrimaryClient();
|
|
42
|
+
fleet = new FleetManager(primary);
|
|
43
|
+
});
|
|
44
|
+
after(async () => {
|
|
45
|
+
primary.stopHealthPolling();
|
|
46
|
+
await workerA.stop();
|
|
47
|
+
await workerB.stop();
|
|
48
|
+
});
|
|
49
|
+
describe("Registration", () => {
|
|
50
|
+
it("should register worker A", () => {
|
|
51
|
+
const req = {
|
|
52
|
+
url: URL_A,
|
|
53
|
+
capabilities: { max_contexts: 3, has_ollama: true, has_memory_daemon: true, available_models: [] },
|
|
54
|
+
};
|
|
55
|
+
const resp = primary.handleRegistration(req);
|
|
56
|
+
workerIdA = resp.worker_id;
|
|
57
|
+
assert.ok(workerIdA);
|
|
58
|
+
});
|
|
59
|
+
it("should register worker B", () => {
|
|
60
|
+
const req = {
|
|
61
|
+
url: URL_B,
|
|
62
|
+
capabilities: { max_contexts: 2, has_ollama: true, has_memory_daemon: true, available_models: [] },
|
|
63
|
+
};
|
|
64
|
+
const resp = primary.handleRegistration(req);
|
|
65
|
+
workerIdB = resp.worker_id;
|
|
66
|
+
assert.ok(workerIdB);
|
|
67
|
+
});
|
|
68
|
+
it("should list both workers", () => {
|
|
69
|
+
assert.equal(primary.getWorkers().length, 2);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("Health Checks — Both Workers", () => {
|
|
73
|
+
it("should get healthy responses from both", async () => {
|
|
74
|
+
const healthA = await primary.checkHealth(workerIdA);
|
|
75
|
+
const healthB = await primary.checkHealth(workerIdB);
|
|
76
|
+
assert.ok(healthA);
|
|
77
|
+
assert.ok(healthB);
|
|
78
|
+
assert.equal(healthA.status, "healthy");
|
|
79
|
+
assert.equal(healthB.status, "healthy");
|
|
80
|
+
});
|
|
81
|
+
it("should poll all and get two healthy", async () => {
|
|
82
|
+
const results = await primary.checkAllHealth();
|
|
83
|
+
assert.equal(results.size, 2);
|
|
84
|
+
for (const [, status] of results) {
|
|
85
|
+
assert.equal(status, "healthy");
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("Context Distribution Across Workers", () => {
|
|
90
|
+
it("should assign project-alpha to worker A", async () => {
|
|
91
|
+
const resp = await primary.assignContext(workerIdA, "project-alpha", "Alpha");
|
|
92
|
+
assert.equal(resp.accepted, true);
|
|
93
|
+
});
|
|
94
|
+
it("should assign project-beta to worker B", async () => {
|
|
95
|
+
const resp = await primary.assignContext(workerIdB, "project-beta", "Beta");
|
|
96
|
+
assert.equal(resp.accepted, true);
|
|
97
|
+
});
|
|
98
|
+
it("should assign project-gamma to worker A", async () => {
|
|
99
|
+
const resp = await primary.assignContext(workerIdA, "project-gamma", "Gamma");
|
|
100
|
+
assert.equal(resp.accepted, true);
|
|
101
|
+
});
|
|
102
|
+
it("should find correct worker for each context", () => {
|
|
103
|
+
assert.equal(primary.findWorkerForContext("project-alpha")?.id, workerIdA);
|
|
104
|
+
assert.equal(primary.findWorkerForContext("project-beta")?.id, workerIdB);
|
|
105
|
+
assert.equal(primary.findWorkerForContext("project-gamma")?.id, workerIdA);
|
|
106
|
+
});
|
|
107
|
+
it("should reject when worker B is at capacity (max 2)", async () => {
|
|
108
|
+
// B already has project-beta (1/2), add one more
|
|
109
|
+
const resp1 = await primary.assignContext(workerIdB, "project-delta", "Delta");
|
|
110
|
+
assert.equal(resp1.accepted, true);
|
|
111
|
+
// Now at 2/2 — next should fail
|
|
112
|
+
const resp2 = await primary.assignContext(workerIdB, "project-epsilon", "Epsilon");
|
|
113
|
+
assert.equal(resp2.accepted, false);
|
|
114
|
+
assert.ok(resp2.reason?.includes("capacity"));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
describe("Status Reporting", () => {
|
|
118
|
+
it("should report working status on worker A", async () => {
|
|
119
|
+
workerA.setActiveContext("project-alpha");
|
|
120
|
+
workerA.setCurrentTask("task-1");
|
|
121
|
+
const report = { activity: "working", current_context: "project-alpha", current_task: "task-1" };
|
|
122
|
+
const status = primary.handleStatusReport(workerIdA, report);
|
|
123
|
+
assert.ok(status);
|
|
124
|
+
assert.equal(status.activity, "working");
|
|
125
|
+
assert.equal(status.current_context, "project-alpha");
|
|
126
|
+
});
|
|
127
|
+
it("should report idle status on worker B", async () => {
|
|
128
|
+
const resp = await fetch(`${URL_B}/status`);
|
|
129
|
+
const body = (await resp.json());
|
|
130
|
+
assert.equal(body.activity, "idle");
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
describe("Memory Sync Endpoints", () => {
|
|
134
|
+
it("should return 501 when no sync handler registered", async () => {
|
|
135
|
+
const resp = await fetch(`${URL_A}/sync/push`, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: { "Content-Type": "application/json" },
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
entries: [],
|
|
140
|
+
episodes: [],
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
// 501 = handler not registered (expected without MemorySync wiring)
|
|
144
|
+
assert.equal(resp.status, 501);
|
|
145
|
+
});
|
|
146
|
+
it("should accept sync push when handler is registered", async () => {
|
|
147
|
+
workerA.onSyncPush(async (_req) => ({
|
|
148
|
+
l3_accepted: 0,
|
|
149
|
+
l2_appended: 0,
|
|
150
|
+
}));
|
|
151
|
+
const resp = await fetch(`${URL_A}/sync/push`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: { "Content-Type": "application/json" },
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
entries: [],
|
|
156
|
+
episodes: [],
|
|
157
|
+
}),
|
|
158
|
+
});
|
|
159
|
+
assert.equal(resp.status, 200);
|
|
160
|
+
const body = await resp.json();
|
|
161
|
+
assert.equal(body.l3_accepted, 0);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
describe("Context Unassignment and Reassignment", () => {
|
|
165
|
+
it("should unassign project-gamma from worker A", async () => {
|
|
166
|
+
const ok = await primary.unassignContext(workerIdA, "project-gamma");
|
|
167
|
+
assert.equal(ok, true);
|
|
168
|
+
});
|
|
169
|
+
it("should no longer find worker for project-gamma", () => {
|
|
170
|
+
assert.equal(primary.findWorkerForContext("project-gamma"), undefined);
|
|
171
|
+
});
|
|
172
|
+
it("should reassign project-gamma to worker B (after freeing a slot)", async () => {
|
|
173
|
+
// Unassign delta from B first
|
|
174
|
+
await primary.unassignContext(workerIdB, "project-delta");
|
|
175
|
+
const resp = await primary.assignContext(workerIdB, "project-gamma", "Gamma moved");
|
|
176
|
+
assert.equal(resp.accepted, true);
|
|
177
|
+
assert.equal(primary.findWorkerForContext("project-gamma")?.id, workerIdB);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
describe("Fleet Dashboard", () => {
|
|
181
|
+
it("should produce a dashboard with current state", async () => {
|
|
182
|
+
const dashboard = await fleet.getDashboard();
|
|
183
|
+
assert.ok(dashboard);
|
|
184
|
+
assert.equal(dashboard.total_workers, 2);
|
|
185
|
+
// Workers should have contexts assigned
|
|
186
|
+
assert.ok(dashboard.workers.length === 2);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("Deregistration", () => {
|
|
190
|
+
it("should deregister worker A", () => {
|
|
191
|
+
assert.equal(primary.deregister(workerIdA), true);
|
|
192
|
+
});
|
|
193
|
+
it("should deregister worker B", () => {
|
|
194
|
+
assert.equal(primary.deregister(workerIdB), true);
|
|
195
|
+
});
|
|
196
|
+
it("should have no workers left", () => {
|
|
197
|
+
assert.equal(primary.getWorkers().length, 0);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
//# sourceMappingURL=fleet-integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-integration.test.js","sourceRoot":"","sources":["../../src/__tests__/fleet-integration.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fleet.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for the worker protocol (Phase 3, Task 3.1).
|
|
3
|
+
*
|
|
4
|
+
* Spins up a real WorkerServer and exercises the PrimaryClient against it.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, before, after } from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { PrimaryClient } from "../fleet/primary-client.js";
|
|
9
|
+
import { WorkerServer } from "../fleet/worker-server.js";
|
|
10
|
+
const TEST_PORT = 19876;
|
|
11
|
+
const WORKER_URL = `http://localhost:${TEST_PORT}`;
|
|
12
|
+
describe("Worker Protocol", () => {
|
|
13
|
+
let primary;
|
|
14
|
+
let worker;
|
|
15
|
+
let workerId;
|
|
16
|
+
before(async () => {
|
|
17
|
+
worker = new WorkerServer({
|
|
18
|
+
workerId: "test-worker-1",
|
|
19
|
+
port: TEST_PORT,
|
|
20
|
+
maxContexts: 2,
|
|
21
|
+
memoryDaemonUrl: "http://localhost:9999",
|
|
22
|
+
ollamaUrl: "http://localhost:11434",
|
|
23
|
+
});
|
|
24
|
+
await worker.start();
|
|
25
|
+
primary = new PrimaryClient();
|
|
26
|
+
});
|
|
27
|
+
after(async () => {
|
|
28
|
+
primary.stopHealthPolling();
|
|
29
|
+
await worker.stop();
|
|
30
|
+
});
|
|
31
|
+
describe("Registration", () => {
|
|
32
|
+
it("should register a worker and return an ID", () => {
|
|
33
|
+
const req = {
|
|
34
|
+
url: WORKER_URL,
|
|
35
|
+
capabilities: {
|
|
36
|
+
max_contexts: 2,
|
|
37
|
+
has_ollama: true,
|
|
38
|
+
has_memory_daemon: true,
|
|
39
|
+
available_models: ["nomic-embed-text"],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const resp = primary.handleRegistration(req);
|
|
43
|
+
workerId = resp.worker_id;
|
|
44
|
+
assert.ok(workerId.startsWith("worker-"));
|
|
45
|
+
assert.ok(resp.registered_at);
|
|
46
|
+
});
|
|
47
|
+
it("should list the registered worker", () => {
|
|
48
|
+
const workers = primary.getWorkers();
|
|
49
|
+
assert.equal(workers.length, 1);
|
|
50
|
+
assert.equal(workers[0].id, workerId);
|
|
51
|
+
assert.equal(workers[0].url, WORKER_URL);
|
|
52
|
+
});
|
|
53
|
+
it("should get a worker by ID", () => {
|
|
54
|
+
const w = primary.getWorker(workerId);
|
|
55
|
+
assert.ok(w);
|
|
56
|
+
assert.equal(w.id, workerId);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe("Health Checks", () => {
|
|
60
|
+
it("should get a healthy response from worker", async () => {
|
|
61
|
+
const health = await primary.checkHealth(workerId);
|
|
62
|
+
assert.ok(health);
|
|
63
|
+
assert.equal(health.worker_id, "test-worker-1");
|
|
64
|
+
assert.equal(health.status, "healthy");
|
|
65
|
+
assert.ok(health.uptime_seconds >= 0);
|
|
66
|
+
assert.equal(health.memory_daemon_ok, true);
|
|
67
|
+
assert.equal(health.ollama_ok, true);
|
|
68
|
+
});
|
|
69
|
+
it("should return null for unknown worker", async () => {
|
|
70
|
+
const health = await primary.checkHealth("nonexistent");
|
|
71
|
+
assert.equal(health, null);
|
|
72
|
+
});
|
|
73
|
+
it("should poll all workers", async () => {
|
|
74
|
+
const results = await primary.checkAllHealth();
|
|
75
|
+
assert.equal(results.size, 1);
|
|
76
|
+
assert.equal(results.get(workerId), "healthy");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("Context Assignment", () => {
|
|
80
|
+
it("should assign a context to a worker", async () => {
|
|
81
|
+
const resp = await primary.assignContext(workerId, "project-alpha", "Alpha project");
|
|
82
|
+
assert.equal(resp.accepted, true);
|
|
83
|
+
assert.equal(resp.context_name, "project-alpha");
|
|
84
|
+
});
|
|
85
|
+
it("should track the assigned context on primary", () => {
|
|
86
|
+
const w = primary.getWorker(workerId);
|
|
87
|
+
assert.ok(w);
|
|
88
|
+
assert.ok(w.assigned_contexts.includes("project-alpha"));
|
|
89
|
+
});
|
|
90
|
+
it("should find worker for context", () => {
|
|
91
|
+
const w = primary.findWorkerForContext("project-alpha");
|
|
92
|
+
assert.ok(w);
|
|
93
|
+
assert.equal(w.id, workerId);
|
|
94
|
+
});
|
|
95
|
+
it("should return undefined for unassigned context", () => {
|
|
96
|
+
const w = primary.findWorkerForContext("nonexistent");
|
|
97
|
+
assert.equal(w, undefined);
|
|
98
|
+
});
|
|
99
|
+
it("should track the assigned context on worker", () => {
|
|
100
|
+
const contexts = worker.getAssignedContexts();
|
|
101
|
+
assert.ok(contexts.includes("project-alpha"));
|
|
102
|
+
});
|
|
103
|
+
it("should assign a second context", async () => {
|
|
104
|
+
const resp = await primary.assignContext(workerId, "project-beta", "Beta project");
|
|
105
|
+
assert.equal(resp.accepted, true);
|
|
106
|
+
});
|
|
107
|
+
it("should reject when at capacity", async () => {
|
|
108
|
+
const resp = await primary.assignContext(workerId, "project-gamma", "Too many");
|
|
109
|
+
assert.equal(resp.accepted, false);
|
|
110
|
+
assert.ok(resp.reason?.includes("capacity"));
|
|
111
|
+
});
|
|
112
|
+
it("should unassign a context", async () => {
|
|
113
|
+
const ok = await primary.unassignContext(workerId, "project-beta");
|
|
114
|
+
assert.equal(ok, true);
|
|
115
|
+
const w = primary.getWorker(workerId);
|
|
116
|
+
assert.ok(w);
|
|
117
|
+
assert.ok(!w.assigned_contexts.includes("project-beta"));
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
describe("Status Reporting", () => {
|
|
121
|
+
it("should report idle status when no task", async () => {
|
|
122
|
+
const resp = await fetch(`${WORKER_URL}/status`);
|
|
123
|
+
const body = (await resp.json());
|
|
124
|
+
assert.equal(body.activity, "idle");
|
|
125
|
+
assert.equal(body.current_context, null);
|
|
126
|
+
assert.equal(body.current_task, null);
|
|
127
|
+
});
|
|
128
|
+
it("should reflect active context and task", async () => {
|
|
129
|
+
worker.setActiveContext("project-alpha");
|
|
130
|
+
worker.setCurrentTask("task-42");
|
|
131
|
+
const resp = await fetch(`${WORKER_URL}/status`);
|
|
132
|
+
const body = (await resp.json());
|
|
133
|
+
assert.equal(body.activity, "working");
|
|
134
|
+
assert.equal(body.current_context, "project-alpha");
|
|
135
|
+
assert.equal(body.current_task, "task-42");
|
|
136
|
+
});
|
|
137
|
+
it("should handle status report on primary side", () => {
|
|
138
|
+
const report = {
|
|
139
|
+
activity: "working",
|
|
140
|
+
current_context: "project-alpha",
|
|
141
|
+
current_task: "task-42",
|
|
142
|
+
};
|
|
143
|
+
const status = primary.handleStatusReport(workerId, report);
|
|
144
|
+
assert.ok(status);
|
|
145
|
+
assert.equal(status.worker_id, workerId);
|
|
146
|
+
assert.equal(status.activity, "working");
|
|
147
|
+
assert.equal(status.current_context, "project-alpha");
|
|
148
|
+
});
|
|
149
|
+
it("should return null for unknown worker status report", () => {
|
|
150
|
+
const report = {
|
|
151
|
+
activity: "idle",
|
|
152
|
+
current_context: null,
|
|
153
|
+
current_task: null,
|
|
154
|
+
};
|
|
155
|
+
const status = primary.handleStatusReport("nonexistent", report);
|
|
156
|
+
assert.equal(status, null);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
describe("Deregistration", () => {
|
|
160
|
+
it("should deregister a worker", () => {
|
|
161
|
+
const ok = primary.deregister(workerId);
|
|
162
|
+
assert.equal(ok, true);
|
|
163
|
+
assert.equal(primary.getWorkers().length, 0);
|
|
164
|
+
});
|
|
165
|
+
it("should return false for unknown worker", () => {
|
|
166
|
+
const ok = primary.deregister("nonexistent");
|
|
167
|
+
assert.equal(ok, false);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
//# sourceMappingURL=fleet.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet.test.js","sourceRoot":"","sources":["../../src/__tests__/fleet.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAOzD,MAAM,SAAS,GAAG,KAAK,CAAC;AACxB,MAAM,UAAU,GAAG,oBAAoB,SAAS,EAAE,CAAC;AAEnD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,OAAsB,CAAC;IAC3B,IAAI,MAAoB,CAAC;IACzB,IAAI,QAAgB,CAAC;IAErB,MAAM,CAAC,KAAK,IAAI,EAAE;QAChB,MAAM,GAAG,IAAI,YAAY,CAAC;YACxB,QAAQ,EAAE,eAAe;YACzB,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,uBAAuB;YACxC,SAAS,EAAE,wBAAwB;SACpC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAErB,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC5B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,GAAG,GAA8B;gBACrC,GAAG,EAAE,UAAU;gBACf,YAAY,EAAE;oBACZ,YAAY,EAAE,CAAC;oBACf,UAAU,EAAE,IAAI;oBAChB,iBAAiB,EAAE,IAAI;oBACvB,gBAAgB,EAAE,CAAC,kBAAkB,CAAC;iBACvC;aACF,CAAC;YAEF,MAAM,IAAI,GAAG,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAC7C,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC;YAE1B,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YACrC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAChC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAChD,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;YAC5C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;YACxD,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;YACvC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC;YAC/C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;YACnD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;YACrF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;YACtD,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,eAAe,CAAC,CAAC;YACxD,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC;YACtD,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC9C,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;YACnF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;YAChF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;YACnE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAEvB,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACtC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACb,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAuB,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACtD,MAAM,CAAC,gBAAgB,CAAC,eAAe,CAAC,CAAC;YACzC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;YAEjC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,SAAS,CAAC,CAAC;YACjD,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAuB,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACvC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;YACpD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,MAAM,GAAuB;gBACjC,QAAQ,EAAE,SAAS;gBACnB,eAAe,EAAE,eAAe;gBAChC,YAAY,EAAE,SAAS;aACxB,CAAC;YAEF,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YAC5D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAClB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,MAAM,GAAuB;gBACjC,QAAQ,EAAE,MAAM;gBAChB,eAAe,EAAE,IAAI;gBACrB,YAAY,EAAE,IAAI;aACnB,CAAC;YAEF,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;YACjE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACvB,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integration.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/integration.test.ts"],"names":[],"mappings":""}
|