@ectplsm/relic 0.2.1 → 0.2.3
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 +54 -31
- 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/create-engram.d.ts +26 -0
- package/dist/core/usecases/create-engram.js +54 -0
- package/dist/core/usecases/delete-engram.d.ts +24 -0
- package/dist/core/usecases/delete-engram.js +46 -0
- package/dist/core/usecases/index.d.ts +2 -0
- package/dist/core/usecases/index.js +2 -0
- 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/create.d.ts +2 -0
- package/dist/interfaces/cli/commands/create.js +143 -0
- package/dist/interfaces/cli/commands/delete.d.ts +2 -0
- package/dist/interfaces/cli/commands/delete.js +113 -0
- 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 +8 -0
- package/dist/interfaces/mcp/index.js +68 -0
- package/dist/shared/config.d.ts +2 -1
- package/dist/shared/config.js +13 -7
- package/dist/shared/templates.d.ts +6 -0
- package/dist/shared/templates.js +65 -0
- 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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|:---:|:---:|
|
|
3
3
|
|
|
4
4
|
# PROJECT RELIC
|
|
5
|
+

|
|
5
6
|
|
|
6
7
|
```
|
|
7
8
|
____ ________ ____________
|
|
@@ -17,6 +18,7 @@ Relic manages AI **Engrams** (memory + personality) and injects them into coding
|
|
|
17
18
|
|
|
18
19
|
## Table of Contents
|
|
19
20
|
|
|
21
|
+
- [Requirements](#requirements)
|
|
20
22
|
- [Install](#install)
|
|
21
23
|
- [Quick Start](#quick-start)
|
|
22
24
|
- [What `relic init` Creates](#what-relic-init-creates)
|
|
@@ -29,9 +31,14 @@ Relic manages AI **Engrams** (memory + personality) and injects them into coding
|
|
|
29
31
|
- [Memory Management](#memory-management)
|
|
30
32
|
- [Configuration](#configuration)
|
|
31
33
|
- [Creating Your Own Engram](#creating-your-own-engram)
|
|
34
|
+
- [Deleting an Engram](#deleting-an-engram)
|
|
32
35
|
- [Domain Glossary](#domain-glossary)
|
|
33
36
|
- [Roadmap](#roadmap)
|
|
34
37
|
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
- Node.js 18 or later
|
|
41
|
+
|
|
35
42
|
## Install
|
|
36
43
|
|
|
37
44
|
<img alt="version badge" src="https://img.shields.io/github/v/release/ectplsm/relic?filter=*.*.*">
|
|
@@ -98,12 +105,14 @@ Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sa
|
|
|
98
105
|
└── engrams/
|
|
99
106
|
├── johnny/
|
|
100
107
|
│ ├── engram.json
|
|
108
|
+
│ ├── manifest.json
|
|
101
109
|
│ ├── SOUL.md
|
|
102
110
|
│ ├── IDENTITY.md
|
|
103
111
|
│ └── memory/
|
|
104
112
|
│ └── YYYY-MM-DD.md
|
|
105
113
|
└── motoko/
|
|
106
114
|
├── engram.json
|
|
115
|
+
├── manifest.json
|
|
107
116
|
├── SOUL.md
|
|
108
117
|
├── IDENTITY.md
|
|
109
118
|
└── memory/
|
|
@@ -112,7 +121,8 @@ Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sa
|
|
|
112
121
|
|
|
113
122
|
- `config.json` stores global Relic settings such as `engramsPath`, `defaultEngram`, `clawPath`, and `memoryWindowSize`.
|
|
114
123
|
- `engrams/<id>/` is one Engram workspace. This is where persona files and memory for that Engram live.
|
|
115
|
-
- `engram.json` stores
|
|
124
|
+
- `engram.json` stores editable profile fields like display name, description, and tags.
|
|
125
|
+
- `manifest.json` stores system-managed fields like the Engram ID and timestamps.
|
|
116
126
|
- `SOUL.md` and `IDENTITY.md` define the persona itself.
|
|
117
127
|
- `memory/YYYY-MM-DD.md` stores dated distilled memory entries. `relic init` seeds an initial memory file for each sample Engram.
|
|
118
128
|
|
|
@@ -123,11 +133,20 @@ As you keep using an Engram, more files are added to the same workspace:
|
|
|
123
133
|
- `USER.md` is created or updated during memory distillation to record user preferences, tendencies, and work style.
|
|
124
134
|
- `~/.relic/hooks/` and `~/.relic/gemini-system-default.md` are created later on first shell launch when hook registration or Gemini prompt caching is needed.
|
|
125
135
|
|
|
136
|
+
### Migration
|
|
137
|
+
|
|
138
|
+
If you want to manually update parts of an existing local setup that changed over time, use:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
relic migrate engrams # migrate legacy engram.json metadata to manifest.json
|
|
142
|
+
relic refresh-samples # refresh bundled sample personas like johnny and motoko
|
|
143
|
+
```
|
|
144
|
+
|
|
126
145
|
## Sample Engrams
|
|
127
146
|
|
|
128
147
|
`relic init` seeds two ready-to-use Engrams. Their SOUL.md and IDENTITY.md follow the [OpenClaw](https://github.com/openclaw/openclaw) format.
|
|
129
148
|
|
|
130
|
-
> **Existing users:**
|
|
149
|
+
> **Existing users:** Run `relic refresh-samples` to update bundled sample personas from the latest templates.
|
|
131
150
|
|
|
132
151
|
### Johnny Silverhand (`johnny`)
|
|
133
152
|
|
|
@@ -266,6 +285,7 @@ Session logs and memory entries are written automatically by a **background hook
|
|
|
266
285
|
|
|
267
286
|
| Tool | Description |
|
|
268
287
|
|------|-------------|
|
|
288
|
+
| `relic_engram_create` | Create a new Engram with optional LLM-generated SOUL.md and IDENTITY.md |
|
|
269
289
|
| `relic_archive_search` | Search the Engram's raw archive by keyword (newest-first) |
|
|
270
290
|
| `relic_archive_pending` | Get un-distilled archive entries since the last distillation (up to 30) |
|
|
271
291
|
| `relic_memory_write` | Write distilled memory to `memory/*.md`, optionally append to `MEMORY.md`, optionally update `USER.md`, and advance the archive cursor |
|
|
@@ -287,6 +307,7 @@ To suppress confirmation dialogs and auto-approve Relic tools across all project
|
|
|
287
307
|
"permissions": {
|
|
288
308
|
"allow": [
|
|
289
309
|
"Edit(~/.relic/engrams/**)",
|
|
310
|
+
"mcp__relic__relic_engram_create",
|
|
290
311
|
"mcp__relic__relic_archive_search",
|
|
291
312
|
"mcp__relic__relic_archive_pending",
|
|
292
313
|
"mcp__relic__relic_memory_write"
|
|
@@ -306,6 +327,9 @@ codex mcp add relic -- relic-mcp
|
|
|
306
327
|
To suppress confirmation dialogs and auto-approve Relic tools, add the following to `~/.codex/config.toml`:
|
|
307
328
|
|
|
308
329
|
```toml
|
|
330
|
+
[mcp_servers.relic.tools.relic_engram_create]
|
|
331
|
+
approval_mode = "approve"
|
|
332
|
+
|
|
309
333
|
[mcp_servers.relic.tools.relic_archive_search]
|
|
310
334
|
approval_mode = "approve"
|
|
311
335
|
|
|
@@ -378,7 +402,7 @@ relic claw inject --engram motoko --yes
|
|
|
378
402
|
Creates a new Engram from an existing Claw agent workspace.
|
|
379
403
|
|
|
380
404
|
What `extract` writes locally:
|
|
381
|
-
- New extract: `engram.json`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `memory/*.md`
|
|
405
|
+
- New extract: `engram.json`, `manifest.json`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `MEMORY.md`, `memory/*.md`
|
|
382
406
|
- `extract --force`: only `SOUL.md` and `IDENTITY.md`
|
|
383
407
|
- `extract --force --name`: `SOUL.md`, `IDENTITY.md`, and `engram.json.name`
|
|
384
408
|
|
|
@@ -509,34 +533,29 @@ CLI flags always take precedence over config values.
|
|
|
509
533
|
|
|
510
534
|
## Creating Your Own Engram
|
|
511
535
|
|
|
512
|
-
|
|
536
|
+
The easiest way to create a new Engram is with `relic create`:
|
|
513
537
|
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
├── USER.md # (optional) User context
|
|
521
|
-
├── MEMORY.md # (optional) Memory index
|
|
522
|
-
├── HEARTBEAT.md # (optional) Periodic reflection
|
|
523
|
-
└── memory/ # (optional) Dated memory entries
|
|
524
|
-
└── 2026-03-21.md
|
|
538
|
+
```bash
|
|
539
|
+
# Fully interactive — prompts for everything
|
|
540
|
+
relic create
|
|
541
|
+
|
|
542
|
+
# Pre-supply some fields
|
|
543
|
+
relic create --id my-agent --name "My Agent" --description "A helpful assistant" --tags "custom,dev"
|
|
525
544
|
```
|
|
526
545
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
"name": "Display Name",
|
|
532
|
-
"description": "A short description",
|
|
533
|
-
"createdAt": "2026-03-21T00:00:00Z",
|
|
534
|
-
"updatedAt": "2026-03-21T00:00:00Z",
|
|
535
|
-
"tags": ["custom"]
|
|
536
|
-
}
|
|
546
|
+
This creates the directory structure, writes `engram.json` / `manifest.json`, and seeds `SOUL.md` / `IDENTITY.md` with OpenClaw-compatible default templates. Customize the persona files, then launch a shell:
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
relic claude my-agent
|
|
537
550
|
```
|
|
538
551
|
|
|
539
|
-
|
|
552
|
+
You can also create Engrams via the `relic_engram_create` MCP tool — LLMs can ask about the desired personality and generate `SOUL.md` / `IDENTITY.md` content through conversation, then call the tool with the results.
|
|
553
|
+
|
|
554
|
+
### Customizing the Persona
|
|
555
|
+
|
|
556
|
+
After running `relic create`, edit `SOUL.md` and `IDENTITY.md` in the Engram directory. These follow the [OpenClaw](https://github.com/openclaw/openclaw) format:
|
|
557
|
+
|
|
558
|
+
**SOUL.md** — The most important file. Defines how the persona behaves:
|
|
540
559
|
```markdown
|
|
541
560
|
# SOUL.md - Who You Are
|
|
542
561
|
|
|
@@ -574,11 +593,14 @@ Each session, you wake up fresh. These files _are_ your memory. Read them. Updat
|
|
|
574
593
|
|
|
575
594
|
See [`templates/engrams/`](templates/engrams/) for full working examples.
|
|
576
595
|
|
|
577
|
-
|
|
596
|
+
## Deleting an Engram
|
|
597
|
+
|
|
578
598
|
```bash
|
|
579
|
-
relic
|
|
599
|
+
relic delete my-agent
|
|
580
600
|
```
|
|
581
601
|
|
|
602
|
+
If the Engram has memory data (`MEMORY.md`, `USER.md`, `memory/*.md`, `archive.md`), you'll need to type the Engram ID to confirm deletion. Use `--force` to skip all prompts.
|
|
603
|
+
|
|
582
604
|
## Domain Glossary
|
|
583
605
|
|
|
584
606
|
| Term | Role | Description |
|
|
@@ -597,10 +619,11 @@ relic config default-engram your-persona
|
|
|
597
619
|
- [x] Claw integration (inject / extract / sync)
|
|
598
620
|
- [x] `relic claw sync` — bidirectional memory sync with Claw workspaces
|
|
599
621
|
- [x] `relic config` — manage default Engram, Claw path, memory window
|
|
600
|
-
- [
|
|
601
|
-
- [
|
|
622
|
+
- [x] `relic create` — interactive Engram creation wizard + MCP tool
|
|
623
|
+
- [x] `relic delete` — safe Engram deletion with memory-aware confirmation
|
|
602
624
|
- [ ] Mikoshi cloud backend (`mikoshi.ectplsm.com`)
|
|
603
|
-
- [ ] `relic
|
|
625
|
+
- [ ] `relic mikoshi login` — authenticate with Mikoshi (OAuth Device Flow)
|
|
626
|
+
- [ ] `relic mikoshi upload` / `relic mikoshi download` / `relic mikoshi sync` — sync Engrams with Mikoshi
|
|
604
627
|
|
|
605
628
|
## License
|
|
606
629
|
|
|
@@ -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";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Engram } from "../entities/engram.js";
|
|
2
|
+
import type { EngramRepository } from "../ports/engram-repository.js";
|
|
3
|
+
export declare class EngramAlreadyExistsError extends Error {
|
|
4
|
+
constructor(id: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class InvalidEngramIdError extends Error {
|
|
7
|
+
constructor(id: string);
|
|
8
|
+
}
|
|
9
|
+
export interface CreateEngramParams {
|
|
10
|
+
id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
tags?: string[];
|
|
14
|
+
soul: string;
|
|
15
|
+
identity: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CreateEngramResult {
|
|
18
|
+
engram: Engram;
|
|
19
|
+
}
|
|
20
|
+
/** ID format: lowercase alphanumeric + hyphens, no leading/trailing hyphen */
|
|
21
|
+
export declare const ENGRAM_ID_PATTERN: RegExp;
|
|
22
|
+
export declare class CreateEngram {
|
|
23
|
+
private readonly repository;
|
|
24
|
+
constructor(repository: EngramRepository);
|
|
25
|
+
execute(params: CreateEngramParams): Promise<CreateEngramResult>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Errors
|
|
3
|
+
// ============================================================
|
|
4
|
+
export class EngramAlreadyExistsError extends Error {
|
|
5
|
+
constructor(id) {
|
|
6
|
+
super(`Engram "${id}" already exists. Delete it first or choose a different ID.`);
|
|
7
|
+
this.name = "EngramAlreadyExistsError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class InvalidEngramIdError extends Error {
|
|
11
|
+
constructor(id) {
|
|
12
|
+
super(`Invalid Engram ID "${id}". Use lowercase letters, numbers, and hyphens only (e.g. "my-agent").`);
|
|
13
|
+
this.name = "InvalidEngramIdError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// ============================================================
|
|
17
|
+
// Usecase
|
|
18
|
+
// ============================================================
|
|
19
|
+
/** ID format: lowercase alphanumeric + hyphens, no leading/trailing hyphen */
|
|
20
|
+
export const ENGRAM_ID_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
21
|
+
export class CreateEngram {
|
|
22
|
+
repository;
|
|
23
|
+
constructor(repository) {
|
|
24
|
+
this.repository = repository;
|
|
25
|
+
}
|
|
26
|
+
async execute(params) {
|
|
27
|
+
// Validate ID format
|
|
28
|
+
if (!ENGRAM_ID_PATTERN.test(params.id)) {
|
|
29
|
+
throw new InvalidEngramIdError(params.id);
|
|
30
|
+
}
|
|
31
|
+
// Check for duplicates
|
|
32
|
+
const existing = await this.repository.get(params.id);
|
|
33
|
+
if (existing) {
|
|
34
|
+
throw new EngramAlreadyExistsError(params.id);
|
|
35
|
+
}
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
const engram = {
|
|
38
|
+
meta: {
|
|
39
|
+
id: params.id,
|
|
40
|
+
name: params.name,
|
|
41
|
+
description: params.description,
|
|
42
|
+
tags: params.tags,
|
|
43
|
+
createdAt: now,
|
|
44
|
+
updatedAt: now,
|
|
45
|
+
},
|
|
46
|
+
files: {
|
|
47
|
+
soul: params.soul,
|
|
48
|
+
identity: params.identity,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
await this.repository.save(engram);
|
|
52
|
+
return { engram };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Engram } from "../entities/engram.js";
|
|
2
|
+
import type { EngramRepository } from "../ports/engram-repository.js";
|
|
3
|
+
export declare class DeleteEngramNotFoundError extends Error {
|
|
4
|
+
constructor(id: string);
|
|
5
|
+
}
|
|
6
|
+
export interface DeleteEngramInfo {
|
|
7
|
+
engram: Engram;
|
|
8
|
+
hasMemory: boolean;
|
|
9
|
+
hasUser: boolean;
|
|
10
|
+
hasArchive: boolean;
|
|
11
|
+
memoryEntryCount: number;
|
|
12
|
+
}
|
|
13
|
+
export declare class DeleteEngram {
|
|
14
|
+
private readonly repository;
|
|
15
|
+
constructor(repository: EngramRepository);
|
|
16
|
+
/**
|
|
17
|
+
* Inspect an Engram before deletion — returns info for confirmation UI.
|
|
18
|
+
*/
|
|
19
|
+
inspect(id: string): Promise<DeleteEngramInfo>;
|
|
20
|
+
/**
|
|
21
|
+
* Actually delete the Engram. Call inspect() first for confirmation.
|
|
22
|
+
*/
|
|
23
|
+
execute(id: string): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Errors
|
|
3
|
+
// ============================================================
|
|
4
|
+
export class DeleteEngramNotFoundError extends Error {
|
|
5
|
+
constructor(id) {
|
|
6
|
+
super(`Engram "${id}" not found.`);
|
|
7
|
+
this.name = "DeleteEngramNotFoundError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
// ============================================================
|
|
11
|
+
// Usecase
|
|
12
|
+
// ============================================================
|
|
13
|
+
export class DeleteEngram {
|
|
14
|
+
repository;
|
|
15
|
+
constructor(repository) {
|
|
16
|
+
this.repository = repository;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Inspect an Engram before deletion — returns info for confirmation UI.
|
|
20
|
+
*/
|
|
21
|
+
async inspect(id) {
|
|
22
|
+
const engram = await this.repository.get(id);
|
|
23
|
+
if (!engram) {
|
|
24
|
+
throw new DeleteEngramNotFoundError(id);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
engram,
|
|
28
|
+
hasMemory: !!engram.files.memory,
|
|
29
|
+
hasUser: !!engram.files.user,
|
|
30
|
+
hasArchive: false, // archive.md is not loaded via EngramFiles; CLI checks separately
|
|
31
|
+
memoryEntryCount: engram.files.memoryEntries
|
|
32
|
+
? Object.keys(engram.files.memoryEntries).length
|
|
33
|
+
: 0,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Actually delete the Engram. Call inspect() first for confirmation.
|
|
38
|
+
*/
|
|
39
|
+
async execute(id) {
|
|
40
|
+
const existing = await this.repository.get(id);
|
|
41
|
+
if (!existing) {
|
|
42
|
+
throw new DeleteEngramNotFoundError(id);
|
|
43
|
+
}
|
|
44
|
+
await this.repository.delete(id);
|
|
45
|
+
}
|
|
46
|
+
}
|