n2-soul 6.0.2 → 6.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.ko.md +78 -8
- package/README.md +81 -9
- package/index.js +1 -1
- package/lib/ark/audit.js +4 -1
- package/lib/config.default.js +2 -0
- package/lib/soul-engine.js +25 -0
- package/package.json +1 -1
- package/sequences/boot.js +18 -9
- package/sequences/work.js +14 -0
- package/tests/README.md +5 -0
- package/{test-ark-integration.js → tests/test-ark-integration.js} +3 -3
package/README.ko.md
CHANGED
|
@@ -5,16 +5,15 @@
|
|
|
5
5
|
**AI 에이전트는 세션이 끝나면 모든 걸 잊어버립니다. Soul이 그걸 해결합니다.**
|
|
6
6
|
**AI 에이전트가 위험한 행동을 할 수도 있습니다. Ark가 그걸 막습니다.**
|
|
7
7
|
|
|
8
|
-
> ### 🚀 v6.
|
|
8
|
+
> ### 🚀 v6.1 업데이트 — 클라우드 저장
|
|
9
9
|
>
|
|
10
|
-
>
|
|
10
|
+
> AI 기억을 **어디에든** 저장하세요 — Google Drive, OneDrive, NAS, 회사 서버, USB. 설정 한 줄이면 끝:
|
|
11
|
+
> ```js
|
|
12
|
+
> DATA_DIR: 'G:/내 드라이브/n2-soul'
|
|
13
|
+
> ```
|
|
14
|
+
> **월 $0. API 키 없음. 새 의존성 없음.** 다른 서비스가 월 $99~$599를 받을 때, Soul은 기존 파일 동기화를 활용합니다. [자세히 →](#️-클라우드-저장--ai-기억을-원하는-곳-어디에든)
|
|
11
15
|
>
|
|
12
|
-
>
|
|
13
|
-
> - `enabled: false` 옵션 없음 — Ark는 항상 켜져 있음 (의도적 설계)
|
|
14
|
-
> - 12개 블랙리스트 규칙, 125개 패턴, 7개 업종별 템플릿 포함
|
|
15
|
-
> - 자기보호: 4계층으로 AI가 방화벽을 비활성화하는 것을 방지
|
|
16
|
-
>
|
|
17
|
-
> v6.0이 **메이저 버전**인 이유: 모든 도구 호출에 수호자가 생겼습니다. [자세히 →](#ark--최후의-방패)
|
|
16
|
+
> **Ark** (v6.0) 포함 — 토큰 비용 0으로 위험한 행동을 차단하는 AI 안전 시스템. [자세히 →](#ark--최후의-방패)
|
|
18
17
|
|
|
19
18
|
Cursor, VS Code Copilot 등 MCP 호환 AI 에이전트와 새 채팅을 시작할 때마다, 에이전트는 이전에 뭘 했는지 전혀 모른 채 처음부터 시작합니다. Soul은 에이전트에게 이런 능력을 부여하는 MCP 서버입니다:
|
|
20
19
|
|
|
@@ -141,6 +140,69 @@ n2_work_end(project, title, summary, todo, entities, insights)
|
|
|
141
140
|
| **시맨틱 검색** | Ollama 임베딩 연동 (nomic-embed-text, 선택사항) |
|
|
142
141
|
| **백업/복원** | 설정 가능한 보존 기간의 증분 백업 |
|
|
143
142
|
| **Ark** | 토큰 비용 0으로 위험한 행동을 차단하는 AI 안전 시스템 (v6.0) |
|
|
143
|
+
| **☁️ 클라우드 저장** | 기억을 어디에든 저장 — Google Drive, NAS, 회사 서버, 아무 경로나 (v6.1) |
|
|
144
|
+
|
|
145
|
+
## ☁️ 클라우드 저장 — AI 기억을 원하는 곳 어디에든
|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
> **설정 한 줄. API 키 없음. 월 요금 없음.**
|
|
150
|
+
|
|
151
|
+
다른 AI 메모리 서비스는 클라우드 저장에 **월 $99~$599**를 받습니다. Soul은 완전히 다른 접근법을 취합니다:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// config.local.js — 이게 전부입니다
|
|
155
|
+
module.exports = {
|
|
156
|
+
DATA_DIR: 'G:/내 드라이브/n2-soul', // Google Drive
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**끝입니다.** AI의 기억이 이제 클라우드에 있습니다. 모든 세션, 인수인계, 원장 기록이 Google Drive가 자동으로 동기화합니다. OAuth도, API 키도, SDK도 필요 없습니다.
|
|
161
|
+
|
|
162
|
+
### 작동 원리
|
|
163
|
+
|
|
164
|
+
Soul은 모든 걸 **일반 JSON 파일**로 저장합니다. OS가 읽을 수 있는 모든 폴더 = Soul의 클라우드. 클라우드 서비스가 동기화를 처리하고 — Soul은 자기가 "클라우드에 있는지"조차 모릅니다.
|
|
165
|
+
|
|
166
|
+
### 지원 저장소
|
|
167
|
+
|
|
168
|
+
| 저장소 | `DATA_DIR` 예시 | 비용 |
|
|
169
|
+
|--------|-----------------|:----:|
|
|
170
|
+
| 📁 **로컬** (기본값) | `./data` | 무료 |
|
|
171
|
+
| ☁️ **Google Drive** | `G:/내 드라이브/n2-soul` | 무료 (15GB) |
|
|
172
|
+
| ☁️ **OneDrive** | `C:/Users/you/OneDrive/n2-soul` | 무료 (5GB) |
|
|
173
|
+
| ☁️ **Dropbox** | `C:/Users/you/Dropbox/n2-soul` | 무료 (2GB) |
|
|
174
|
+
| 🖥️ **NAS** | `Z:/n2-soul` | 자체 장비 |
|
|
175
|
+
| 🏢 **회사 서버** | `\\\\server\\shared\\n2-soul` | 자체 인프라 |
|
|
176
|
+
| 🔌 **USB 드라이브** | `E:/n2-soul` | $10 |
|
|
177
|
+
| 🐧 **Linux (rclone)** | `~/gdrive/n2-soul` | 무료 |
|
|
178
|
+
|
|
179
|
+
### 다른 AI 메모리 서비스와 비교
|
|
180
|
+
|
|
181
|
+
| | Soul | mem0 | Zep AI |
|
|
182
|
+
|---|:---:|:---:|:---:|
|
|
183
|
+
| **클라우드 저장** | 설정 한 줄 | API 연동 | API 연동 |
|
|
184
|
+
| **월 비용** | **$0** | $99/월 | $599/월 |
|
|
185
|
+
| **설정 시간** | 10초 | 수 시간 | 수 시간 |
|
|
186
|
+
| **벤더 종속** | 없음 — 당신의 파일 | API 종속 | API 종속 |
|
|
187
|
+
| **데이터 소유권** | 100% 당신의 것 | 그들의 서버 | 그들의 서버 |
|
|
188
|
+
| **오프라인 작동** | 가능 | 불가 | 불가 |
|
|
189
|
+
| **자체 호스팅** | 아무 경로나 = 클라우드 | 엔터프라이즈 전용 | 엔터프라이즈 전용 |
|
|
190
|
+
|
|
191
|
+
### 팀 공유
|
|
192
|
+
|
|
193
|
+
여러 에이전트가 **같은 네트워크 경로**를 가리키면 = 즉석 공유 메모리:
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
// 팀원 A // 팀원 B
|
|
197
|
+
DATA_DIR: '\\\\server\\team\\n2-soul' DATA_DIR: '\\\\server\\team\\n2-soul'
|
|
198
|
+
// 같은 프로젝트 데이터, 공유 인수인계, 공유 두뇌!
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 왜 이게 되는가
|
|
202
|
+
|
|
203
|
+
> *"최고의 클라우드 연동은 연동이 아예 없는 것이다."*
|
|
204
|
+
|
|
205
|
+
Soul의 데이터는 **100% 일반 JSON 파일** — `soul-board.json`, 원장 기록, 두뇌 메모리. 폴더를 미러링하는 동기화 서비스(Google Drive, OneDrive, Dropbox, Syncthing, rsync)라면 뭐든 완벽하게 작동합니다. 데이터베이스 마이그레이션도, API 버전도, SDK 업데이트도 필요 없습니다. 그냥 파일입니다.
|
|
144
206
|
|
|
145
207
|
## Ark — 최후의 방패
|
|
146
208
|
|
|
@@ -246,6 +308,14 @@ module.exports = {
|
|
|
246
308
|
};
|
|
247
309
|
```
|
|
248
310
|
|
|
311
|
+
### 보안 철학
|
|
312
|
+
|
|
313
|
+
**`.n2` 규칙의 투명성**: 안전 규칙은 **의도적으로 공개 + 감사 가능**하도록 설계되었습니다. 숨겨진 규칙, 난독화된 패턴, "우리를 믿어라" 블랙박스가 없습니다. 사용자가 직접 읽고 커스터마이즈하고 검증할 수 있어야 합니다.
|
|
314
|
+
|
|
315
|
+
**시크릿은 로컬만**: `config.local.js`는 gitignore 처리되어 배포되지 않습니다. 사용자의 머신에만 존재합니다. Soul은 API 키, 비밀번호, 인증 정보를 전송/저장/처리하지 않습니다.
|
|
316
|
+
|
|
317
|
+
**저장소 주권**: 모든 데이터(원장, 메모리, 감사 로그)는 **당신의 머신**에 남습니다. 백업 위치 선택은 자유 — 로컬 SQLite, Google Drive 폴더, 자체 클라우드 어디든. Soul은 외부로 통신하지 않습니다.
|
|
318
|
+
|
|
249
319
|
## 데이터 디렉토리
|
|
250
320
|
|
|
251
321
|
모든 런타임 데이터는 `data/`에 저장됩니다 (gitignored, 자동 생성):
|
package/README.md
CHANGED
|
@@ -6,21 +6,20 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://nodejs.org)
|
|
8
8
|
[](https://www.npmjs.com/package/n2-soul)
|
|
9
|
-
[](https://github.com/choihyunsus/soul#️-cloud-storage--store-your-ai-memory-anywhere)
|
|
10
10
|
|
|
11
11
|
**Your AI agent forgets everything when a session ends. Soul fixes that.**
|
|
12
12
|
**Your AI agent might do something dangerous. Ark stops that.**
|
|
13
13
|
|
|
14
|
-
> ### 🚀 What's New in v6.
|
|
14
|
+
> ### 🚀 What's New in v6.1 — Cloud Storage
|
|
15
15
|
>
|
|
16
|
-
>
|
|
16
|
+
> Store your AI memory **anywhere** — Google Drive, OneDrive, NAS, company server, USB. Just one line:
|
|
17
|
+
> ```js
|
|
18
|
+
> DATA_DIR: 'G:/My Drive/n2-soul'
|
|
19
|
+
> ```
|
|
20
|
+
> **$0/month. Zero API keys. Zero new dependencies.** While others charge $99~$599/month, Soul uses your existing file sync. [Learn more →](#️-cloud-storage--store-your-ai-memory-anywhere)
|
|
17
21
|
>
|
|
18
|
-
> -
|
|
19
|
-
> - There is no `enabled: false` — Ark is always on by design
|
|
20
|
-
> - Ships with 12 blacklist rules, 125 patterns, and 7 industry templates
|
|
21
|
-
> - Self-protection: 4 layers prevent a rogue AI from disabling the firewall
|
|
22
|
-
>
|
|
23
|
-
> This is why v6.0 is a **major version**: every tool call now has a guardian. [Learn more →](#ark-firewall)
|
|
22
|
+
> Also includes **Ark** (v6.0) — built-in AI safety that blocks dangerous actions at zero token cost. [Learn more →](#ark--the-last-shield)
|
|
24
23
|
|
|
25
24
|
Every time you start a new chat with Cursor, VS Code Copilot, or any MCP-compatible AI agent, it starts from zero — no memory of what it did before. Soul is an MCP server that gives your agents:
|
|
26
25
|
|
|
@@ -41,6 +40,7 @@ Every time you start a new chat with Cursor, VS Code Copilot, or any MCP-compati
|
|
|
41
40
|
- [Token Efficiency](#token-efficiency)
|
|
42
41
|
- [How It Works](#how-it-works)
|
|
43
42
|
- [Features](#features)
|
|
43
|
+
- [Cloud Storage](#️-cloud-storage--store-your-ai-memory-anywhere)
|
|
44
44
|
- [Available Tools](#available-tools)
|
|
45
45
|
- [Real-World Example](#real-world-example)
|
|
46
46
|
- [Rust Compiler (n2c)](#rust-compiler-n2c)
|
|
@@ -185,6 +185,70 @@ n2_work_end(project, title, summary, todo, entities, insights)
|
|
|
185
185
|
| **Semantic Search** | Optional Ollama embedding (nomic-embed-text) |
|
|
186
186
|
| **Backup/Restore** | Incremental backups with configurable retention |
|
|
187
187
|
| **Ark** | 🆕 Built-in AI safety — blocks dangerous actions at zero token cost |
|
|
188
|
+
| **Cloud Storage** | 🆕 Store memory anywhere — Google Drive, NAS, network server, any path (v6.1) |
|
|
189
|
+
|
|
190
|
+
## ☁️ Cloud Storage — Store Your AI Memory Anywhere
|
|
191
|
+
|
|
192
|
+

|
|
193
|
+
|
|
194
|
+
> **One line of config. Zero API keys. Zero monthly fees.**
|
|
195
|
+
|
|
196
|
+
Other AI memory services charge **$99~$599/month** for cloud storage. Soul takes a radically different approach:
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
// config.local.js — This is ALL you need
|
|
200
|
+
module.exports = {
|
|
201
|
+
DATA_DIR: 'G:/My Drive/n2-soul', // Google Drive
|
|
202
|
+
};
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**That's it.** Your AI memory is now in the cloud. Every session, every handoff, every ledger entry — automatically synced by Google Drive. No OAuth, no API keys, no SDK.
|
|
206
|
+
|
|
207
|
+
### How It Works
|
|
208
|
+
|
|
209
|
+
Soul stores everything as **plain JSON files**. Any folder that your OS can read = Soul's cloud. The cloud provider handles sync — Soul doesn't even know it's "in the cloud."
|
|
210
|
+
|
|
211
|
+
### Supported Storage
|
|
212
|
+
|
|
213
|
+
| Storage | Example `DATA_DIR` | Cost |
|
|
214
|
+
|---------|-------------------|:----:|
|
|
215
|
+
| 📁 **Local** (default) | `./data` | Free |
|
|
216
|
+
| ☁️ **Google Drive** | `G:/My Drive/n2-soul` | Free (15GB) |
|
|
217
|
+
| ☁️ **OneDrive** | `C:/Users/you/OneDrive/n2-soul` | Free (5GB) |
|
|
218
|
+
| ☁️ **Dropbox** | `C:/Users/you/Dropbox/n2-soul` | Free (2GB) |
|
|
219
|
+
| 🖥️ **NAS** | `Z:/n2-soul` | Your hardware |
|
|
220
|
+
| 🏢 **Company Server** | `\\\\server\\shared\\n2-soul` | Your infra |
|
|
221
|
+
| 🔌 **USB Drive** | `E:/n2-soul` | $10 |
|
|
222
|
+
| 🐧 **Linux (rclone)** | `~/gdrive/n2-soul` | Free |
|
|
223
|
+
|
|
224
|
+
### vs. Other AI Memory Services
|
|
225
|
+
|
|
226
|
+
| | Soul | mem0 | Zep AI |
|
|
227
|
+
|---|:---:|:---:|:---:|
|
|
228
|
+
| **Cloud storage** | One line of config | API integration | API integration |
|
|
229
|
+
| **Monthly cost** | **$0** | $99/mo | $599/mo |
|
|
230
|
+
| **Setup time** | 10 seconds | Hours | Hours |
|
|
231
|
+
| **Vendor lock-in** | None — it's your files | API dependent | API dependent |
|
|
232
|
+
| **Data ownership** | 100% yours | Their servers | Their servers |
|
|
233
|
+
| **Works offline** | Yes | No | No |
|
|
234
|
+
| **Self-hosted option** | Any path = cloud | Enterprise only | Enterprise only |
|
|
235
|
+
|
|
236
|
+
### Team Sharing
|
|
237
|
+
|
|
238
|
+
Point multiple agents to the **same network path** = instant shared memory:
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// Team member A // Team member B
|
|
242
|
+
DATA_DIR: '\\\\server\\team\\n2-soul' DATA_DIR: '\\\\server\\team\\n2-soul'
|
|
243
|
+
// Same project data, shared handoffs, shared brain!
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Why This Works
|
|
247
|
+
|
|
248
|
+
> *"The best cloud integration is no integration at all."*
|
|
249
|
+
|
|
250
|
+
Soul's data is **100% plain JSON files** — `soul-board.json`, ledger entries, brain memory. Any sync service that mirrors folders (Google Drive, OneDrive, Dropbox, Syncthing, rsync) works perfectly because there's nothing to integrate. No database migrations, no API versions, no SDK updates. Just files.
|
|
251
|
+
|
|
188
252
|
|
|
189
253
|
## Ark — The Last Shield
|
|
190
254
|
|
|
@@ -383,6 +447,14 @@ module.exports = {
|
|
|
383
447
|
|
|
384
448
|
> **Note:** There is no `enabled: false` option. This is by design. The lock cannot unlock itself.
|
|
385
449
|
|
|
450
|
+
### Security Philosophy
|
|
451
|
+
|
|
452
|
+
**Transparency of `.n2` Rules**: Safety rules are **intentionally public and auditable**. This is by design — users should be able to read, customize, and verify exactly what is being blocked. There are no hidden rules, no obfuscated patterns, and no "trust us" black boxes. Open rules build trust.
|
|
453
|
+
|
|
454
|
+
**Secrets stay local**: `config.local.js` is gitignored and never distributed. It exists only on the user's machine. Soul does not transmit, store, or process any API keys, passwords, or credentials.
|
|
455
|
+
|
|
456
|
+
**Storage sovereignty**: All data (ledger, memory, audit logs) stays on **your machine**. You choose where backups go — local SQLite, Google Drive folder, or your own cloud. Soul never phones home.
|
|
457
|
+
|
|
386
458
|
## Available Tools
|
|
387
459
|
|
|
388
460
|
| Tool | Description |
|
package/index.js
CHANGED
package/lib/ark/audit.js
CHANGED
|
@@ -18,7 +18,7 @@ class AuditLogger {
|
|
|
18
18
|
constructor(options = {}) {
|
|
19
19
|
this.dir = options.dir || path.join(process.cwd(), 'data', 'audit');
|
|
20
20
|
this.enabled = options.enabled !== false;
|
|
21
|
-
this.maxAgeDays = options.maxAgeDays ||
|
|
21
|
+
this.maxAgeDays = options.maxAgeDays || 7;
|
|
22
22
|
this.logPasses = options.logPasses || false;
|
|
23
23
|
this._buffer = [];
|
|
24
24
|
this._flushInterval = null;
|
|
@@ -30,6 +30,9 @@ class AuditLogger {
|
|
|
30
30
|
// Flush buffer every 5 seconds
|
|
31
31
|
this._flushInterval = setInterval(() => this._flush(), 5000);
|
|
32
32
|
this._flushInterval.unref(); // Don't keep process alive just for audit flush
|
|
33
|
+
|
|
34
|
+
// Auto-cleanup old logs on startup
|
|
35
|
+
try { this.cleanup(); } catch (e) { /* silent */ }
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
|
package/lib/config.default.js
CHANGED
|
@@ -4,6 +4,8 @@ const path = require('path');
|
|
|
4
4
|
module.exports = {
|
|
5
5
|
// All paths derived dynamically. No hardcoding.
|
|
6
6
|
SOUL_ROOT: path.resolve(__dirname, '..'),
|
|
7
|
+
// Cloud Storage (v6.1): Change DATA_DIR in config.local.js to any cloud sync folder
|
|
8
|
+
// e.g., 'G:/My Drive/n2-soul' or '\\\\server\\shared\\n2-soul'
|
|
7
9
|
DATA_DIR: path.resolve(__dirname, '..', 'data'),
|
|
8
10
|
TIMEZONE: 'Asia/Seoul', // Override with config.local.js for other timezones
|
|
9
11
|
AGENTS_DIR: null, // Auto-detected by agent-registry.js
|
package/lib/soul-engine.js
CHANGED
|
@@ -134,6 +134,31 @@ class SoulEngine {
|
|
|
134
134
|
return { id, path: path.join(dir, fileName) };
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
+
// -- All Projects (sorted by recency) --
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* List all projects sorted by most recently updated.
|
|
141
|
+
* Safe: returns [] if no projects directory exists.
|
|
142
|
+
* @returns {{ name: string, updatedAt: string, board: object }[]}
|
|
143
|
+
*/
|
|
144
|
+
listAllProjects() {
|
|
145
|
+
const projectsDir = path.join(this.dataDir, 'projects');
|
|
146
|
+
if (!fs.existsSync(projectsDir)) return [];
|
|
147
|
+
try {
|
|
148
|
+
return fs.readdirSync(projectsDir, { withFileTypes: true })
|
|
149
|
+
.filter(d => d.isDirectory() && !d.name.startsWith('_'))
|
|
150
|
+
.filter(d => fs.existsSync(this.boardPath(d.name)))
|
|
151
|
+
.map(d => {
|
|
152
|
+
const board = this.readBoard(d.name);
|
|
153
|
+
return { name: d.name, updatedAt: board.updatedAt || '', board };
|
|
154
|
+
})
|
|
155
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
156
|
+
} catch (e) {
|
|
157
|
+
logError('soul-engine:listAllProjects', e);
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
137
162
|
// -- File Index --
|
|
138
163
|
|
|
139
164
|
readFileIndex(projectName) {
|
package/package.json
CHANGED
package/sequences/boot.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Soul MCP
|
|
1
|
+
// Soul MCP v6.0 — Boot sequence. Handoff + Entity/Core Memory injection + KV-Cache restore.
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const { readJson, today, nowISO, logError } = require('../lib/utils');
|
|
@@ -46,10 +46,19 @@ function registerBootSequence(server, z, config) {
|
|
|
46
46
|
lines.push(`Ark: LOAD FAILED — ${e.message}`);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
// -- Soul Board: handoff + TODO --
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
// -- Soul Board: handoff + TODO (auto-detect latest project) --
|
|
50
|
+
let targetProject = project;
|
|
51
|
+
if (!targetProject) {
|
|
52
|
+
const allProjects = engine.listAllProjects();
|
|
53
|
+
if (allProjects.length > 0) {
|
|
54
|
+
targetProject = allProjects[0].name;
|
|
55
|
+
lines.push(`\n📍 Auto-detected latest project: ${targetProject}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (targetProject) {
|
|
60
|
+
const board = engine.readBoard(targetProject);
|
|
61
|
+
lines.push(`\n--- ${targetProject} | v${board.state.version || '?'} | ${board.state.health || '?'} ---`);
|
|
53
62
|
|
|
54
63
|
if (board.handoff && board.handoff.summary) {
|
|
55
64
|
lines.push(`Handoff(${board.handoff.from}): ${board.handoff.summary}`);
|
|
@@ -70,13 +79,13 @@ function registerBootSequence(server, z, config) {
|
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
// -- KV-Cache auto-load --
|
|
73
|
-
if (
|
|
82
|
+
if (targetProject && config.KV_CACHE?.enabled && config.KV_CACHE?.autoLoadOnBoot) {
|
|
74
83
|
try {
|
|
75
84
|
const { SoulKVCache } = require('../lib/kv-cache');
|
|
76
85
|
const kvCache = new SoulKVCache(config.DATA_DIR, config.KV_CACHE);
|
|
77
|
-
const snap = kvCache.load(
|
|
86
|
+
const snap = kvCache.load(targetProject);
|
|
78
87
|
if (snap) {
|
|
79
|
-
setKvChainParent(
|
|
88
|
+
setKvChainParent(targetProject, snap.id);
|
|
80
89
|
const level = snap._level || 'auto';
|
|
81
90
|
const tokens = snap._promptTokens || '?';
|
|
82
91
|
lines.push(`\nKV-Cache: ${level} | ~${tokens}t | ${snap.id.slice(0, 8)}`);
|
|
@@ -105,7 +114,7 @@ function registerBootSequence(server, z, config) {
|
|
|
105
114
|
lines.push(`⚠️ Core Memory: ${e.message}`);
|
|
106
115
|
}
|
|
107
116
|
|
|
108
|
-
lines.push(`\n--- Soul Boot
|
|
117
|
+
lines.push(`\n--- Soul Boot v6.0 complete ---`);
|
|
109
118
|
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
110
119
|
}
|
|
111
120
|
);
|
package/sequences/work.js
CHANGED
|
@@ -7,6 +7,19 @@ const { SoulEngine } = require('../lib/soul-engine');
|
|
|
7
7
|
// In-memory work session state per project
|
|
8
8
|
const activeSessions = {};
|
|
9
9
|
|
|
10
|
+
// TTL: auto-expire stale sessions (24 hours, checked every hour)
|
|
11
|
+
const SESSION_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
+
const _sessionGcTimer = setInterval(() => {
|
|
13
|
+
const now = Date.now();
|
|
14
|
+
for (const [project, session] of Object.entries(activeSessions)) {
|
|
15
|
+
if (session._createdMs && (now - session._createdMs) > SESSION_TTL_MS) {
|
|
16
|
+
delete activeSessions[project];
|
|
17
|
+
logError('work:ttl', `Expired stale session: ${project} (agent: ${session.agent})`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}, 60 * 60 * 1000);
|
|
21
|
+
_sessionGcTimer.unref(); // Don't prevent Node.js from exiting
|
|
22
|
+
|
|
10
23
|
// ── Helper: recursively walk files in a directory ──
|
|
11
24
|
function walkFiles(dir, callback, maxDepth, depth = 0) {
|
|
12
25
|
if (depth > maxDepth) return;
|
|
@@ -45,6 +58,7 @@ function registerWorkSequence(server, z, config) {
|
|
|
45
58
|
agent,
|
|
46
59
|
task,
|
|
47
60
|
startedAt: nowISO(),
|
|
61
|
+
_createdMs: Date.now(),
|
|
48
62
|
filesCreated: [],
|
|
49
63
|
filesModified: [],
|
|
50
64
|
filesDeleted: [],
|
package/tests/README.md
ADDED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// n2-ark + n2-soul integration test — pure last shield
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { createArk } = require('
|
|
3
|
+
const { createArk } = require('../lib/ark');
|
|
4
4
|
|
|
5
5
|
const ark = createArk({
|
|
6
|
-
rulesDir: path.join(__dirname, 'rules'),
|
|
7
|
-
auditDir: path.join(__dirname, 'data', 'ark-audit'),
|
|
6
|
+
rulesDir: path.join(__dirname, '..', 'rules'),
|
|
7
|
+
auditDir: path.join(__dirname, '..', 'data', 'ark-audit'),
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
let passed = 0;
|