@ectplsm/relic 0.2.0 → 0.2.2
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 +121 -35
- package/dist/adapters/local/local-engram-repository.d.ts +5 -1
- package/dist/adapters/local/local-engram-repository.js +53 -19
- package/dist/core/entities/engram.d.ts +56 -14
- package/dist/core/entities/engram.js +15 -6
- package/dist/core/entities/index.d.ts +1 -1
- package/dist/core/entities/index.js +1 -1
- package/dist/core/usecases/extract.d.ts +17 -0
- package/dist/core/usecases/extract.js +70 -16
- package/dist/core/usecases/index.d.ts +4 -2
- package/dist/core/usecases/index.js +2 -0
- package/dist/core/usecases/inject.d.ts +16 -1
- package/dist/core/usecases/inject.js +51 -17
- package/dist/core/usecases/migrate-engrams.d.ts +18 -0
- package/dist/core/usecases/migrate-engrams.js +49 -0
- package/dist/core/usecases/refresh-samples.d.ts +21 -0
- package/dist/core/usecases/refresh-samples.js +60 -0
- package/dist/interfaces/cli/commands/claw.js +143 -12
- package/dist/interfaces/cli/commands/migrate.d.ts +2 -0
- package/dist/interfaces/cli/commands/migrate.js +31 -0
- package/dist/interfaces/cli/commands/refresh-samples.d.ts +2 -0
- package/dist/interfaces/cli/commands/refresh-samples.js +24 -0
- package/dist/interfaces/cli/index.js +4 -0
- package/dist/shared/config.d.ts +2 -1
- package/dist/shared/config.js +13 -7
- package/package.json +1 -1
- package/templates/engrams/johnny/IDENTITY.md +10 -0
- package/templates/engrams/johnny/SOUL.md +41 -0
- package/templates/engrams/motoko/IDENTITY.md +19 -1
- package/templates/engrams/motoko/SOUL.md +58 -1
package/README.md
CHANGED
|
@@ -42,27 +42,52 @@ npm install -g @ectplsm/relic
|
|
|
42
42
|
|
|
43
43
|
## Quick Start
|
|
44
44
|
|
|
45
|
+
### 1. Initialize
|
|
46
|
+
|
|
45
47
|
```bash
|
|
46
|
-
# Initialize — creates config and sample Engrams
|
|
47
48
|
relic init
|
|
48
49
|
# → Prompts: "Set a default Engram? (press Enter for "johnny", or enter ID, or "n" to skip):"
|
|
49
50
|
|
|
50
|
-
# List available Engrams
|
|
51
|
-
relic
|
|
51
|
+
relic list # List available Engrams
|
|
52
|
+
relic config default-engram motoko # (Optional) Set your default Engram
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Set Up Memory (MCP)
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
relic show motoko
|
|
57
|
+
Register the MCP server so the Construct can search past conversations and distill memories. Pick your shell:
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
59
|
+
```bash
|
|
60
|
+
# Claude Code
|
|
61
|
+
claude mcp add --scope user relic -- relic-mcp
|
|
62
|
+
|
|
63
|
+
# Codex CLI
|
|
64
|
+
codex mcp add relic -- relic-mcp
|
|
65
|
+
|
|
66
|
+
# Gemini CLI — add to ~/.gemini/settings.json:
|
|
67
|
+
# { "mcpServers": { "relic": { "command": "relic-mcp", "trust": true } } }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
> For auto-approval setup and per-shell details, see [MCP Server](#mcp-server).
|
|
71
|
+
|
|
72
|
+
### 3. Launch a Shell
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
relic claude # Uses default Engram
|
|
76
|
+
relic claude --engram motoko # Specify explicitly
|
|
58
77
|
relic codex
|
|
59
78
|
relic gemini
|
|
60
|
-
|
|
61
|
-
# Or specify explicitly
|
|
62
|
-
relic claude --engram motoko
|
|
63
|
-
relic codex --engram johnny
|
|
64
79
|
```
|
|
65
80
|
|
|
81
|
+
### 4. Organize Memories
|
|
82
|
+
|
|
83
|
+
As you use a Construct, conversation logs are automatically saved to `archive.md` by background hooks. To distill these into lasting memory, periodically tell the Construct:
|
|
84
|
+
|
|
85
|
+
> **"Organize my memories"**
|
|
86
|
+
|
|
87
|
+
The Construct will review recent conversations, extract key facts and decisions into `memory/*.md`, promote important long-term insights to `MEMORY.md`, and update your preferences in `USER.md`. These distilled memories are then loaded into future sessions automatically.
|
|
88
|
+
|
|
89
|
+
> For details on the memory system, see [Memory Management](#memory-management).
|
|
90
|
+
|
|
66
91
|
## What `relic init` Creates
|
|
67
92
|
|
|
68
93
|
Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sample Engrams under `~/.relic/engrams/`.
|
|
@@ -73,12 +98,14 @@ Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sa
|
|
|
73
98
|
└── engrams/
|
|
74
99
|
├── johnny/
|
|
75
100
|
│ ├── engram.json
|
|
101
|
+
│ ├── manifest.json
|
|
76
102
|
│ ├── SOUL.md
|
|
77
103
|
│ ├── IDENTITY.md
|
|
78
104
|
│ └── memory/
|
|
79
105
|
│ └── YYYY-MM-DD.md
|
|
80
106
|
└── motoko/
|
|
81
107
|
├── engram.json
|
|
108
|
+
├── manifest.json
|
|
82
109
|
├── SOUL.md
|
|
83
110
|
├── IDENTITY.md
|
|
84
111
|
└── memory/
|
|
@@ -87,9 +114,12 @@ Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sa
|
|
|
87
114
|
|
|
88
115
|
- `config.json` stores global Relic settings such as `engramsPath`, `defaultEngram`, `clawPath`, and `memoryWindowSize`.
|
|
89
116
|
- `engrams/<id>/` is one Engram workspace. This is where persona files and memory for that Engram live.
|
|
90
|
-
- `engram.json` stores
|
|
117
|
+
- `engram.json` stores editable profile fields like display name, description, and tags.
|
|
118
|
+
- `manifest.json` stores system-managed fields like the Engram ID and timestamps.
|
|
91
119
|
- `SOUL.md` and `IDENTITY.md` define the persona itself.
|
|
92
120
|
- `memory/YYYY-MM-DD.md` stores dated distilled memory entries. `relic init` seeds an initial memory file for each sample Engram.
|
|
121
|
+
- `relic migrate engrams` can be used to front-load legacy Engrams into the new `manifest.json` format, although normal Engram reads also migrate automatically.
|
|
122
|
+
- `relic refresh-samples` refreshes bundled sample personas like `johnny` and `motoko` without touching memory or archive files.
|
|
93
123
|
|
|
94
124
|
As you keep using an Engram, more files are added to the same workspace:
|
|
95
125
|
|
|
@@ -314,11 +344,23 @@ Add to `~/.gemini/settings.json`:
|
|
|
314
344
|
|
|
315
345
|
Relic Engrams are natively compatible with [OpenClaw](https://github.com/openclaw/openclaw) workspaces — their file structure maps 1:1 (SOUL.md, IDENTITY.md, memory/, etc.). For other Claw-derived frameworks (Nanobot, gitagent, etc.) that fold identity into SOUL.md, the `--merge-identity` flag merges IDENTITY.md into SOUL.md on inject. Combined with `--dir`, Relic can target any Claw-compatible workspace.
|
|
316
346
|
|
|
317
|
-
Agent Name = Engram ID.
|
|
347
|
+
Current rule: **Agent Name = Engram ID**. Relic treats them as the same name by default. This keeps Claw integration simple: once Engram and agent names diverge, Relic has to introduce explicit mapping logic, which adds complexity that the current workflow does not need.
|
|
348
|
+
|
|
349
|
+
All Claw commands live under `relic claw`:
|
|
350
|
+
|
|
351
|
+
### Command Summary
|
|
352
|
+
|
|
353
|
+
| Command | Direction | Description |
|
|
354
|
+
|---------|-----------|-------------|
|
|
355
|
+
| `relic claw inject -e <id>` | Relic → Claw | Push persona + auto-sync (`--yes` skips overwrite confirmation, `--no-sync` skips sync, `--merge-identity` for non-OpenClaw) |
|
|
356
|
+
| `relic claw extract -a <name>` | Claw → Relic | New import or persona-only overwrite, then auto-sync that target (`--force`, `--yes`, `--no-sync`) |
|
|
357
|
+
| `relic claw sync` | Relic ↔ Claw | Bidirectional merge (memory, MEMORY.md, USER.md; `--target` limits sync to one target) |
|
|
318
358
|
|
|
319
359
|
### Inject — Push an Engram into a Claw workspace
|
|
320
360
|
|
|
321
|
-
|
|
361
|
+
Writes the persona files (`SOUL.md`, `IDENTITY.md`) into the agent workspace, then syncs `USER.md` and memory files (`MEMORY.md`, `memory/*.md`). The sync is bidirectional and merge-based, not a blind overwrite. `AGENTS.md` and `HEARTBEAT.md` remain under Claw's control.
|
|
362
|
+
|
|
363
|
+
If persona files already exist in the target workspace and differ from the local Relic Engram, `inject` asks for confirmation by default. Use `--yes` to skip the prompt. If the target persona already matches, Relic skips the persona rewrite and only runs the memory sync.
|
|
322
364
|
|
|
323
365
|
> **Note:** The Claw agent must already exist (e.g. `openclaw agents add <name>`). Inject writes persona files into an existing workspace — it does not create new agents.
|
|
324
366
|
|
|
@@ -326,20 +368,26 @@ Injects persona files (SOUL.md, IDENTITY.md) into the agent's workspace director
|
|
|
326
368
|
# Inject Engram "motoko" → workspace-motoko/
|
|
327
369
|
relic claw inject --engram motoko
|
|
328
370
|
|
|
329
|
-
# Inject into a differently-named agent
|
|
330
|
-
relic claw inject --engram motoko --to main
|
|
331
|
-
# → workspace/ receives motoko's persona
|
|
332
|
-
|
|
333
371
|
# Override Claw directory (or configure once with: relic config claw-path)
|
|
334
372
|
relic claw inject --engram motoko --dir /path/to/.fooclaw
|
|
335
373
|
|
|
336
374
|
# Non-OpenClaw frameworks: merge IDENTITY.md into SOUL.md
|
|
337
375
|
relic claw inject --engram motoko --dir ~/.nanobot --merge-identity
|
|
376
|
+
|
|
377
|
+
# Skip overwrite confirmation if persona files differ
|
|
378
|
+
relic claw inject --engram motoko --yes
|
|
338
379
|
```
|
|
339
380
|
|
|
340
|
-
### Extract — Import a Claw agent as
|
|
381
|
+
### Extract — Import a Claw agent as an Engram
|
|
382
|
+
|
|
383
|
+
Creates a new Engram from an existing Claw agent workspace.
|
|
384
|
+
|
|
385
|
+
What `extract` writes locally:
|
|
386
|
+
- New extract: `engram.json`, `manifest.json`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `memory/*.md`
|
|
387
|
+
- `extract --force`: only `SOUL.md` and `IDENTITY.md`
|
|
388
|
+
- `extract --force --name`: `SOUL.md`, `IDENTITY.md`, and `engram.json.name`
|
|
341
389
|
|
|
342
|
-
|
|
390
|
+
After `extract`, Relic automatically runs a targeted sync for that same Engram/agent target. Use `--no-sync` to skip it.
|
|
343
391
|
|
|
344
392
|
```bash
|
|
345
393
|
# Extract from the default (main) agent
|
|
@@ -351,18 +399,32 @@ relic claw extract --agent johnny
|
|
|
351
399
|
# Set a custom display name
|
|
352
400
|
relic claw extract --agent analyst --name "Data Analyst"
|
|
353
401
|
|
|
402
|
+
# Overwrite local persona files from the Claw workspace
|
|
403
|
+
relic claw extract --agent johnny --force
|
|
404
|
+
|
|
405
|
+
# Skip overwrite confirmation
|
|
406
|
+
relic claw extract --agent johnny --force --yes
|
|
407
|
+
|
|
408
|
+
# Skip the automatic targeted sync after extract
|
|
409
|
+
relic claw extract --agent johnny --no-sync
|
|
410
|
+
|
|
354
411
|
# Override Claw directory
|
|
355
412
|
relic claw extract --agent johnny --dir /path/to/.fooclaw
|
|
356
413
|
```
|
|
357
414
|
|
|
358
415
|
### Sync — Bidirectional merge
|
|
359
416
|
|
|
360
|
-
Merges `memory/*.md`, `MEMORY.md`, and `USER.md` between matching Engram/agent
|
|
417
|
+
Merges `memory/*.md`, `MEMORY.md`, and `USER.md` between matching Engram/agent targets. Only targets where both the Engram and agent exist are synced. Also runs automatically after `inject` (skip with `--no-sync`).
|
|
418
|
+
|
|
419
|
+
By default, `sync` scans all matching targets. Use `--target <id>` to sync only one target by shared Engram/agent name.
|
|
361
420
|
|
|
362
421
|
```bash
|
|
363
|
-
# Sync all matching
|
|
422
|
+
# Sync all matching targets
|
|
364
423
|
relic claw sync
|
|
365
424
|
|
|
425
|
+
# Sync only one matching target
|
|
426
|
+
relic claw sync --target johnny
|
|
427
|
+
|
|
366
428
|
# Override Claw directory
|
|
367
429
|
relic claw sync --dir /path/to/.fooclaw
|
|
368
430
|
```
|
|
@@ -372,13 +434,30 @@ Merge rules:
|
|
|
372
434
|
- Same content → skipped
|
|
373
435
|
- Different content → merged (deduplicated) and written to both sides
|
|
374
436
|
|
|
375
|
-
###
|
|
376
|
-
|
|
377
|
-
| Command |
|
|
378
|
-
|
|
379
|
-
| `
|
|
380
|
-
| `
|
|
381
|
-
| `
|
|
437
|
+
### Behavior Matrix
|
|
438
|
+
|
|
439
|
+
| Command | State | Flags | Result |
|
|
440
|
+
|---------|------|------|------|
|
|
441
|
+
| `inject` | Workspace missing | none | Fail and ask you to create the agent first |
|
|
442
|
+
| `inject` | Persona matches local Engram | none | Skip persona rewrite, then auto-sync that target |
|
|
443
|
+
| `inject` | Persona differs from local Engram | none | Ask for confirmation before overwriting persona, then auto-sync that target |
|
|
444
|
+
| `inject` | Persona differs from local Engram | `--yes` | Overwrite persona without confirmation, then auto-sync that target |
|
|
445
|
+
| `inject` | any successful inject | `--no-sync` | Skip the automatic targeted sync |
|
|
446
|
+
| `extract` | Local Engram missing | none | Create a new Engram from workspace files, then auto-sync that target |
|
|
447
|
+
| `extract` | Local Engram missing | `--force` | Same as normal new extract, then auto-sync that target |
|
|
448
|
+
| `extract` | Local Engram exists | none | Fail and require `--force` |
|
|
449
|
+
| `extract` | Local Engram exists, no persona drift | `--force` | Skip persona overwrite, then auto-sync that target |
|
|
450
|
+
| `extract` | Local Engram exists, persona differs | `--force` | Ask for confirmation before overwriting `SOUL.md` / `IDENTITY.md`, then auto-sync that target |
|
|
451
|
+
| `extract` | Local Engram exists, persona differs | `--force --yes` | Overwrite `SOUL.md` / `IDENTITY.md` without confirmation, then auto-sync that target |
|
|
452
|
+
| `extract` | any successful extract | `--no-sync` | Skip the automatic targeted sync |
|
|
453
|
+
| `sync` | no target | none | Scan and sync all matching targets |
|
|
454
|
+
| `sync` | explicit target | `--target <id>` | Sync one matching target where `agentName = engramId` |
|
|
455
|
+
|
|
456
|
+
Notes:
|
|
457
|
+
- "Persona" means `SOUL.md` and `IDENTITY.md`
|
|
458
|
+
- `extract --force` only overwrites `SOUL.md` and `IDENTITY.md`
|
|
459
|
+
- `extract --force` does not overwrite `USER.md`, `MEMORY.md`, or `memory/*.md`
|
|
460
|
+
- If `--name` is provided together with `extract --force`, Relic also updates `engram.json.name`
|
|
382
461
|
|
|
383
462
|
## Memory Management
|
|
384
463
|
|
|
@@ -439,7 +518,8 @@ Create a directory under `~/.relic/engrams/` with the following structure:
|
|
|
439
518
|
|
|
440
519
|
```
|
|
441
520
|
~/.relic/engrams/your-persona/
|
|
442
|
-
├── engram.json #
|
|
521
|
+
├── engram.json # Editable profile (name, description, tags)
|
|
522
|
+
├── manifest.json # System-managed identity (id, createdAt, updatedAt)
|
|
443
523
|
├── SOUL.md # Core directive — how the persona thinks and acts
|
|
444
524
|
├── IDENTITY.md # Name, tone, background, personality
|
|
445
525
|
├── AGENTS.md # (optional) Tool usage policies
|
|
@@ -453,15 +533,21 @@ Create a directory under `~/.relic/engrams/` with the following structure:
|
|
|
453
533
|
**engram.json:**
|
|
454
534
|
```json
|
|
455
535
|
{
|
|
456
|
-
"id": "your-persona",
|
|
457
536
|
"name": "Display Name",
|
|
458
537
|
"description": "A short description",
|
|
459
|
-
"createdAt": "2026-03-21T00:00:00Z",
|
|
460
|
-
"updatedAt": "2026-03-21T00:00:00Z",
|
|
461
538
|
"tags": ["custom"]
|
|
462
539
|
}
|
|
463
540
|
```
|
|
464
541
|
|
|
542
|
+
**manifest.json:**
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"id": "your-persona",
|
|
546
|
+
"createdAt": "2026-03-21T00:00:00Z",
|
|
547
|
+
"updatedAt": "2026-03-21T00:00:00Z"
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
465
551
|
**SOUL.md** — The most important file. Defines how the persona behaves. Follows the [OpenClaw](https://github.com/openclaw/openclaw) format:
|
|
466
552
|
```markdown
|
|
467
553
|
# SOUL.md - Who You Are
|
|
@@ -523,9 +609,9 @@ relic config default-engram your-persona
|
|
|
523
609
|
- [x] Claw integration (inject / extract / sync)
|
|
524
610
|
- [x] `relic claw sync` — bidirectional memory sync with Claw workspaces
|
|
525
611
|
- [x] `relic config` — manage default Engram, Claw path, memory window
|
|
526
|
-
- [ ] `relic login` — authenticate with Mikoshi (OAuth Device Flow)
|
|
527
|
-
- [ ] `relic push` / `relic pull` — sync Engrams with Mikoshi
|
|
528
612
|
- [ ] Mikoshi cloud backend (`mikoshi.ectplsm.com`)
|
|
613
|
+
- [ ] `relic mikoshi login` — authenticate with Mikoshi (OAuth Device Flow)
|
|
614
|
+
- [ ] `relic mikoshi upload` / `relic mikoshi download` / `relic mikoshi sync` — sync Engrams with Mikoshi
|
|
529
615
|
- [ ] `relic create` — interactive Engram creation wizard
|
|
530
616
|
|
|
531
617
|
## License
|
|
@@ -6,7 +6,8 @@ import type { EngramRepository } from "../../core/ports/engram-repository.js";
|
|
|
6
6
|
*
|
|
7
7
|
* ディレクトリ構造:
|
|
8
8
|
* {basePath}/{engramId}/
|
|
9
|
-
* ├── engram.json (
|
|
9
|
+
* ├── engram.json (ユーザー編集可能なプロフィール)
|
|
10
|
+
* ├── manifest.json (システム管理の識別子・タイムスタンプ)
|
|
10
11
|
* ├── SOUL.md
|
|
11
12
|
* ├── IDENTITY.md
|
|
12
13
|
* ├── AGENTS.md (optional)
|
|
@@ -24,5 +25,8 @@ export declare class LocalEngramRepository implements EngramRepository {
|
|
|
24
25
|
save(engram: Engram): Promise<void>;
|
|
25
26
|
delete(id: string): Promise<void>;
|
|
26
27
|
private readMeta;
|
|
28
|
+
private toProfile;
|
|
29
|
+
private toManifest;
|
|
30
|
+
private writeMetaFiles;
|
|
27
31
|
private readFiles;
|
|
28
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile, writeFile, mkdir, rm } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import { EngramMetaSchema } from "../../core/entities/engram.js";
|
|
4
|
+
import { EngramManifestSchema, EngramMetaSchema, EngramProfileSchema, } from "../../core/entities/engram.js";
|
|
5
5
|
/**
|
|
6
6
|
* OpenClaw互換のファイル名マッピング
|
|
7
7
|
* EngramFiles のキー → 実ファイル名
|
|
@@ -14,7 +14,8 @@ const FILE_MAP = {
|
|
|
14
14
|
memory: "MEMORY.md",
|
|
15
15
|
heartbeat: "HEARTBEAT.md",
|
|
16
16
|
};
|
|
17
|
-
const
|
|
17
|
+
const PROFILE_FILE = "engram.json";
|
|
18
|
+
const MANIFEST_FILE = "manifest.json";
|
|
18
19
|
const MEMORY_DIR = "memory";
|
|
19
20
|
/**
|
|
20
21
|
* LocalEngramRepository — ローカルファイルシステム上の
|
|
@@ -22,7 +23,8 @@ const MEMORY_DIR = "memory";
|
|
|
22
23
|
*
|
|
23
24
|
* ディレクトリ構造:
|
|
24
25
|
* {basePath}/{engramId}/
|
|
25
|
-
* ├── engram.json (
|
|
26
|
+
* ├── engram.json (ユーザー編集可能なプロフィール)
|
|
27
|
+
* ├── manifest.json (システム管理の識別子・タイムスタンプ)
|
|
26
28
|
* ├── SOUL.md
|
|
27
29
|
* ├── IDENTITY.md
|
|
28
30
|
* ├── AGENTS.md (optional)
|
|
@@ -45,13 +47,9 @@ export class LocalEngramRepository {
|
|
|
45
47
|
const dirs = entries.filter((e) => e.isDirectory());
|
|
46
48
|
const metas = [];
|
|
47
49
|
for (const dir of dirs) {
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
const raw = await readFile(metaPath, "utf-8");
|
|
52
|
-
const parsed = EngramMetaSchema.safeParse(JSON.parse(raw));
|
|
53
|
-
if (parsed.success) {
|
|
54
|
-
metas.push(parsed.data);
|
|
50
|
+
const meta = await this.readMeta(join(this.basePath, dir.name));
|
|
51
|
+
if (meta) {
|
|
52
|
+
metas.push(meta);
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
55
|
return metas;
|
|
@@ -61,7 +59,7 @@ export class LocalEngramRepository {
|
|
|
61
59
|
if (!existsSync(engramDir)) {
|
|
62
60
|
return null;
|
|
63
61
|
}
|
|
64
|
-
const meta = await this.readMeta(engramDir);
|
|
62
|
+
const meta = await this.readMeta(engramDir, { migrateLegacy: true });
|
|
65
63
|
if (!meta)
|
|
66
64
|
return null;
|
|
67
65
|
const files = await this.readFiles(engramDir);
|
|
@@ -70,8 +68,7 @@ export class LocalEngramRepository {
|
|
|
70
68
|
async save(engram) {
|
|
71
69
|
const engramDir = join(this.basePath, engram.meta.id);
|
|
72
70
|
await mkdir(engramDir, { recursive: true });
|
|
73
|
-
|
|
74
|
-
await writeFile(join(engramDir, META_FILE), JSON.stringify(engram.meta, null, 2), "utf-8");
|
|
71
|
+
await this.writeMetaFiles(engramDir, engram.meta);
|
|
75
72
|
// 必須ファイル書き込み
|
|
76
73
|
for (const [key, filename] of Object.entries(FILE_MAP)) {
|
|
77
74
|
const content = engram.files[key];
|
|
@@ -95,13 +92,50 @@ export class LocalEngramRepository {
|
|
|
95
92
|
}
|
|
96
93
|
}
|
|
97
94
|
// --- private ---
|
|
98
|
-
async readMeta(engramDir) {
|
|
99
|
-
const
|
|
100
|
-
if (!existsSync(
|
|
95
|
+
async readMeta(engramDir, options) {
|
|
96
|
+
const profilePath = join(engramDir, PROFILE_FILE);
|
|
97
|
+
if (!existsSync(profilePath))
|
|
101
98
|
return null;
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
99
|
+
const profileRaw = JSON.parse(await readFile(profilePath, "utf-8"));
|
|
100
|
+
const manifestPath = join(engramDir, MANIFEST_FILE);
|
|
101
|
+
if (existsSync(manifestPath)) {
|
|
102
|
+
const profile = EngramProfileSchema.safeParse(profileRaw);
|
|
103
|
+
if (!profile.success)
|
|
104
|
+
return null;
|
|
105
|
+
const manifest = EngramManifestSchema.safeParse(JSON.parse(await readFile(manifestPath, "utf-8")));
|
|
106
|
+
if (!manifest.success)
|
|
107
|
+
return null;
|
|
108
|
+
return {
|
|
109
|
+
...profile.data,
|
|
110
|
+
...manifest.data,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// 後方互換: 旧形式では engram.json に profile + manifest が同居していた
|
|
114
|
+
const legacy = EngramMetaSchema.safeParse(profileRaw);
|
|
115
|
+
if (!legacy.success)
|
|
116
|
+
return null;
|
|
117
|
+
if (options?.migrateLegacy) {
|
|
118
|
+
await this.writeMetaFiles(engramDir, legacy.data);
|
|
119
|
+
}
|
|
120
|
+
return legacy.data;
|
|
121
|
+
}
|
|
122
|
+
toProfile(meta) {
|
|
123
|
+
return {
|
|
124
|
+
name: meta.name,
|
|
125
|
+
description: meta.description,
|
|
126
|
+
tags: meta.tags,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
toManifest(meta) {
|
|
130
|
+
return {
|
|
131
|
+
id: meta.id,
|
|
132
|
+
createdAt: meta.createdAt,
|
|
133
|
+
updatedAt: meta.updatedAt,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async writeMetaFiles(engramDir, meta) {
|
|
137
|
+
await writeFile(join(engramDir, PROFILE_FILE), JSON.stringify(this.toProfile(meta), null, 2), "utf-8");
|
|
138
|
+
await writeFile(join(engramDir, MANIFEST_FILE), JSON.stringify(this.toManifest(meta), null, 2), "utf-8");
|
|
105
139
|
}
|
|
106
140
|
async readFiles(engramDir) {
|
|
107
141
|
const files = {};
|
|
@@ -37,31 +37,72 @@ export declare const EngramFileSchema: z.ZodObject<{
|
|
|
37
37
|
}>;
|
|
38
38
|
export type EngramFiles = z.infer<typeof EngramFileSchema>;
|
|
39
39
|
/**
|
|
40
|
-
* Engram
|
|
40
|
+
* Engramプロフィール — ユーザーが編集可能な表示用メタデータ
|
|
41
41
|
*/
|
|
42
|
-
export declare const
|
|
43
|
-
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
44
|
-
id: z.ZodString;
|
|
42
|
+
export declare const EngramProfileSchema: z.ZodObject<{
|
|
45
43
|
/** 表示名 (例: "攻殻機動隊の少佐") */
|
|
46
44
|
name: z.ZodString;
|
|
47
45
|
/** 説明 */
|
|
48
46
|
description: z.ZodOptional<z.ZodString>;
|
|
47
|
+
/** タグ */
|
|
48
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
49
|
+
}, "strip", z.ZodTypeAny, {
|
|
50
|
+
name: string;
|
|
51
|
+
description?: string | undefined;
|
|
52
|
+
tags?: string[] | undefined;
|
|
53
|
+
}, {
|
|
54
|
+
name: string;
|
|
55
|
+
description?: string | undefined;
|
|
56
|
+
tags?: string[] | undefined;
|
|
57
|
+
}>;
|
|
58
|
+
export type EngramProfile = z.infer<typeof EngramProfileSchema>;
|
|
59
|
+
/**
|
|
60
|
+
* Engramマニフェスト — システム管理の不変識別子と監査情報
|
|
61
|
+
*/
|
|
62
|
+
export declare const EngramManifestSchema: z.ZodObject<{
|
|
63
|
+
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
64
|
+
id: z.ZodString;
|
|
49
65
|
/** 作成日時 */
|
|
50
66
|
createdAt: z.ZodString;
|
|
51
67
|
/** 最終更新日時 */
|
|
52
68
|
updatedAt: z.ZodString;
|
|
69
|
+
}, "strip", z.ZodTypeAny, {
|
|
70
|
+
id: string;
|
|
71
|
+
createdAt: string;
|
|
72
|
+
updatedAt: string;
|
|
73
|
+
}, {
|
|
74
|
+
id: string;
|
|
75
|
+
createdAt: string;
|
|
76
|
+
updatedAt: string;
|
|
77
|
+
}>;
|
|
78
|
+
export type EngramManifest = z.infer<typeof EngramManifestSchema>;
|
|
79
|
+
/**
|
|
80
|
+
* Engramメタデータ — プロフィールとマニフェストを結合した利用時ビュー
|
|
81
|
+
*/
|
|
82
|
+
export declare const EngramMetaSchema: z.ZodObject<{
|
|
83
|
+
/** 表示名 (例: "攻殻機動隊の少佐") */
|
|
84
|
+
name: z.ZodString;
|
|
85
|
+
/** 説明 */
|
|
86
|
+
description: z.ZodOptional<z.ZodString>;
|
|
53
87
|
/** タグ */
|
|
54
88
|
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
89
|
+
} & {
|
|
90
|
+
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
91
|
+
id: z.ZodString;
|
|
92
|
+
/** 作成日時 */
|
|
93
|
+
createdAt: z.ZodString;
|
|
94
|
+
/** 最終更新日時 */
|
|
95
|
+
updatedAt: z.ZodString;
|
|
55
96
|
}, "strip", z.ZodTypeAny, {
|
|
56
|
-
id: string;
|
|
57
97
|
name: string;
|
|
98
|
+
id: string;
|
|
58
99
|
createdAt: string;
|
|
59
100
|
updatedAt: string;
|
|
60
101
|
description?: string | undefined;
|
|
61
102
|
tags?: string[] | undefined;
|
|
62
103
|
}, {
|
|
63
|
-
id: string;
|
|
64
104
|
name: string;
|
|
105
|
+
id: string;
|
|
65
106
|
createdAt: string;
|
|
66
107
|
updatedAt: string;
|
|
67
108
|
description?: string | undefined;
|
|
@@ -74,28 +115,29 @@ export type EngramMeta = z.infer<typeof EngramMetaSchema>;
|
|
|
74
115
|
*/
|
|
75
116
|
export declare const EngramSchema: z.ZodObject<{
|
|
76
117
|
meta: z.ZodObject<{
|
|
77
|
-
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
78
|
-
id: z.ZodString;
|
|
79
118
|
/** 表示名 (例: "攻殻機動隊の少佐") */
|
|
80
119
|
name: z.ZodString;
|
|
81
120
|
/** 説明 */
|
|
82
121
|
description: z.ZodOptional<z.ZodString>;
|
|
122
|
+
/** タグ */
|
|
123
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
124
|
+
} & {
|
|
125
|
+
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
126
|
+
id: z.ZodString;
|
|
83
127
|
/** 作成日時 */
|
|
84
128
|
createdAt: z.ZodString;
|
|
85
129
|
/** 最終更新日時 */
|
|
86
130
|
updatedAt: z.ZodString;
|
|
87
|
-
/** タグ */
|
|
88
|
-
tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
89
131
|
}, "strip", z.ZodTypeAny, {
|
|
90
|
-
id: string;
|
|
91
132
|
name: string;
|
|
133
|
+
id: string;
|
|
92
134
|
createdAt: string;
|
|
93
135
|
updatedAt: string;
|
|
94
136
|
description?: string | undefined;
|
|
95
137
|
tags?: string[] | undefined;
|
|
96
138
|
}, {
|
|
97
|
-
id: string;
|
|
98
139
|
name: string;
|
|
140
|
+
id: string;
|
|
99
141
|
createdAt: string;
|
|
100
142
|
updatedAt: string;
|
|
101
143
|
description?: string | undefined;
|
|
@@ -135,8 +177,8 @@ export declare const EngramSchema: z.ZodObject<{
|
|
|
135
177
|
}>;
|
|
136
178
|
}, "strip", z.ZodTypeAny, {
|
|
137
179
|
meta: {
|
|
138
|
-
id: string;
|
|
139
180
|
name: string;
|
|
181
|
+
id: string;
|
|
140
182
|
createdAt: string;
|
|
141
183
|
updatedAt: string;
|
|
142
184
|
description?: string | undefined;
|
|
@@ -153,8 +195,8 @@ export declare const EngramSchema: z.ZodObject<{
|
|
|
153
195
|
};
|
|
154
196
|
}, {
|
|
155
197
|
meta: {
|
|
156
|
-
id: string;
|
|
157
198
|
name: string;
|
|
199
|
+
id: string;
|
|
158
200
|
createdAt: string;
|
|
159
201
|
updatedAt: string;
|
|
160
202
|
description?: string | undefined;
|
|
@@ -23,22 +23,31 @@ export const EngramFileSchema = z.object({
|
|
|
23
23
|
memoryEntries: z.record(z.string(), z.string()).optional(),
|
|
24
24
|
});
|
|
25
25
|
/**
|
|
26
|
-
* Engram
|
|
26
|
+
* Engramプロフィール — ユーザーが編集可能な表示用メタデータ
|
|
27
27
|
*/
|
|
28
|
-
export const
|
|
29
|
-
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
30
|
-
id: z.string(),
|
|
28
|
+
export const EngramProfileSchema = z.object({
|
|
31
29
|
/** 表示名 (例: "攻殻機動隊の少佐") */
|
|
32
30
|
name: z.string(),
|
|
33
31
|
/** 説明 */
|
|
34
32
|
description: z.string().optional(),
|
|
33
|
+
/** タグ */
|
|
34
|
+
tags: z.array(z.string()).optional(),
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Engramマニフェスト — システム管理の不変識別子と監査情報
|
|
38
|
+
*/
|
|
39
|
+
export const EngramManifestSchema = z.object({
|
|
40
|
+
/** 一意識別子 (例: "ghost-in-the-shell") */
|
|
41
|
+
id: z.string(),
|
|
35
42
|
/** 作成日時 */
|
|
36
43
|
createdAt: z.string().datetime(),
|
|
37
44
|
/** 最終更新日時 */
|
|
38
45
|
updatedAt: z.string().datetime(),
|
|
39
|
-
/** タグ */
|
|
40
|
-
tags: z.array(z.string()).optional(),
|
|
41
46
|
});
|
|
47
|
+
/**
|
|
48
|
+
* Engramメタデータ — プロフィールとマニフェストを結合した利用時ビュー
|
|
49
|
+
*/
|
|
50
|
+
export const EngramMetaSchema = EngramProfileSchema.merge(EngramManifestSchema);
|
|
42
51
|
/**
|
|
43
52
|
* Engram — 完全な人格データセット
|
|
44
53
|
* メタデータとファイル群の統合体
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { EngramSchema, EngramFileSchema, EngramMetaSchema, ConstructStatusSchema, ShellTypeSchema, type Engram, type EngramFiles, type EngramMeta, type ConstructStatus, type ShellType, } from "./engram.js";
|
|
1
|
+
export { EngramSchema, EngramFileSchema, EngramProfileSchema, EngramManifestSchema, EngramMetaSchema, ConstructStatusSchema, ShellTypeSchema, type Engram, type EngramFiles, type EngramProfile, type EngramManifest, type EngramMeta, type ConstructStatus, type ShellType, } from "./engram.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { EngramSchema, EngramFileSchema, EngramMetaSchema, ConstructStatusSchema, ShellTypeSchema, } from "./engram.js";
|
|
1
|
+
export { EngramSchema, EngramFileSchema, EngramProfileSchema, EngramManifestSchema, EngramMetaSchema, ConstructStatusSchema, ShellTypeSchema, } from "./engram.js";
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { EngramRepository } from "../ports/engram-repository.js";
|
|
2
|
+
export type ExtractPersonaFileDiff = "missing" | "same" | "different";
|
|
3
|
+
export interface ExtractPersonaDiffResult {
|
|
4
|
+
engramId: string;
|
|
5
|
+
engramName: string;
|
|
6
|
+
sourcePath: string;
|
|
7
|
+
existing: boolean;
|
|
8
|
+
name: ExtractPersonaFileDiff;
|
|
9
|
+
soul: ExtractPersonaFileDiff;
|
|
10
|
+
identity: ExtractPersonaFileDiff;
|
|
11
|
+
overwriteRequired: boolean;
|
|
12
|
+
}
|
|
2
13
|
export interface ExtractResult {
|
|
3
14
|
engramId: string;
|
|
4
15
|
engramName: string;
|
|
@@ -14,10 +25,16 @@ export interface ExtractResult {
|
|
|
14
25
|
export declare class Extract {
|
|
15
26
|
private readonly repository;
|
|
16
27
|
constructor(repository: EngramRepository);
|
|
28
|
+
inspectPersona(agentName: string, options?: {
|
|
29
|
+
name?: string;
|
|
30
|
+
openclawDir?: string;
|
|
31
|
+
}): Promise<ExtractPersonaDiffResult>;
|
|
17
32
|
execute(agentName: string, options?: {
|
|
18
33
|
name?: string;
|
|
19
34
|
openclawDir?: string;
|
|
35
|
+
force?: boolean;
|
|
20
36
|
}): Promise<ExtractResult>;
|
|
37
|
+
private comparePersonaFile;
|
|
21
38
|
private readFiles;
|
|
22
39
|
}
|
|
23
40
|
export declare class WorkspaceNotFoundError extends Error {
|