@ectplsm/relic 0.5.2 → 0.5.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.
Files changed (31) hide show
  1. package/README.md +27 -4
  2. package/dist/adapters/shells/codex-hook.d.ts +3 -3
  3. package/dist/adapters/shells/codex-hook.js +12 -11
  4. package/dist/adapters/shells/codex-paths.d.ts +11 -0
  5. package/dist/adapters/shells/codex-paths.js +23 -0
  6. package/dist/adapters/shells/codex-shell.js +7 -5
  7. package/dist/interfaces/cli/index.js +0 -0
  8. package/dist/interfaces/mcp/index.js +0 -0
  9. package/package.json +3 -2
  10. package/dist/adapters/shells/copilot-shell.d.ts +0 -14
  11. package/dist/adapters/shells/copilot-shell.js +0 -43
  12. package/dist/adapters/shells/trust-registrar.d.ts +0 -19
  13. package/dist/adapters/shells/trust-registrar.js +0 -141
  14. package/dist/core/usecases/inbox-search.d.ts +0 -20
  15. package/dist/core/usecases/inbox-search.js +0 -46
  16. package/dist/core/usecases/inbox-write.d.ts +0 -27
  17. package/dist/core/usecases/inbox-write.js +0 -72
  18. package/dist/core/usecases/memory-search.d.ts +0 -23
  19. package/dist/core/usecases/memory-search.js +0 -59
  20. package/dist/core/usecases/mikoshi-clone.d.ts +0 -29
  21. package/dist/core/usecases/mikoshi-clone.js +0 -94
  22. package/dist/interfaces/cli/commands/extract.d.ts +0 -2
  23. package/dist/interfaces/cli/commands/extract.js +0 -37
  24. package/dist/interfaces/cli/commands/inject.d.ts +0 -2
  25. package/dist/interfaces/cli/commands/inject.js +0 -34
  26. package/dist/interfaces/cli/commands/sync.d.ts +0 -2
  27. package/dist/interfaces/cli/commands/sync.js +0 -47
  28. package/dist/shared/memory-inbox.d.ts +0 -78
  29. package/dist/shared/memory-inbox.js +0 -168
  30. package/dist/shared/session-recorder.d.ts +0 -47
  31. package/dist/shared/session-recorder.js +0 -112
@@ -1,59 +0,0 @@
1
- /**
2
- * MemorySearch — Engramのメモリエントリをキーワード検索する
3
- */
4
- export class MemorySearch {
5
- repository;
6
- constructor(repository) {
7
- this.repository = repository;
8
- }
9
- async search(engramId, query, limit = 5) {
10
- const engram = await this.repository.get(engramId);
11
- if (!engram) {
12
- throw new MemoryEngramNotFoundError(engramId);
13
- }
14
- if (!engram.files.memoryEntries) {
15
- return [];
16
- }
17
- const queryLower = query.toLowerCase();
18
- const results = [];
19
- // Search entries from newest to oldest
20
- const entries = Object.entries(engram.files.memoryEntries).sort(([a], [b]) => b.localeCompare(a));
21
- for (const [date, content] of entries) {
22
- const lines = content.split("\n");
23
- const matchedLines = lines.filter((line) => line.toLowerCase().includes(queryLower));
24
- if (matchedLines.length > 0) {
25
- results.push({ date, content, matchedLines });
26
- }
27
- if (results.length >= limit)
28
- break;
29
- }
30
- return results;
31
- }
32
- async get(engramId, date) {
33
- const engram = await this.repository.get(engramId);
34
- if (!engram) {
35
- throw new MemoryEngramNotFoundError(engramId);
36
- }
37
- const content = engram.files.memoryEntries?.[date];
38
- if (!content) {
39
- return null;
40
- }
41
- return { date, content };
42
- }
43
- async listDates(engramId) {
44
- const engram = await this.repository.get(engramId);
45
- if (!engram) {
46
- throw new MemoryEngramNotFoundError(engramId);
47
- }
48
- if (!engram.files.memoryEntries) {
49
- return [];
50
- }
51
- return Object.keys(engram.files.memoryEntries).sort((a, b) => b.localeCompare(a));
52
- }
53
- }
54
- export class MemoryEngramNotFoundError extends Error {
55
- constructor(id) {
56
- super(`Engram "${id}" not found`);
57
- this.name = "MemoryEngramNotFoundError";
58
- }
59
- }
@@ -1,29 +0,0 @@
1
- import type { EngramRepository } from "../ports/engram-repository.js";
2
- import type { MikoshiClient } from "../ports/mikoshi.js";
3
- export interface MikoshiCloneResult {
4
- engramId: string;
5
- engramName: string;
6
- cloudEngramId: string;
7
- }
8
- export declare class MikoshiCloneAlreadyExistsError extends Error {
9
- readonly engramId: string;
10
- constructor(engramId: string);
11
- }
12
- export declare class MikoshiCloneCloudNotFoundError extends Error {
13
- readonly sourceEngramId: string;
14
- constructor(sourceEngramId: string);
15
- }
16
- export declare class MikoshiClonePersonaMissingError extends Error {
17
- readonly cloudEngramId: string;
18
- constructor(cloudEngramId: string);
19
- }
20
- export declare class MikoshiClone {
21
- private readonly localRepo;
22
- private readonly mikoshi;
23
- constructor(localRepo: EngramRepository, mikoshi: MikoshiClient);
24
- /**
25
- * Clone a remote Engram from Mikoshi to local.
26
- * Fails if the local Engram already exists.
27
- */
28
- execute(engramId: string): Promise<MikoshiCloneResult>;
29
- }
@@ -1,94 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Errors
3
- // ---------------------------------------------------------------------------
4
- export class MikoshiCloneAlreadyExistsError extends Error {
5
- engramId;
6
- constructor(engramId) {
7
- super(`Engram "${engramId}" already exists locally. Use "relic mikoshi pull" to update it.`);
8
- this.engramId = engramId;
9
- this.name = "MikoshiCloneAlreadyExistsError";
10
- }
11
- }
12
- export class MikoshiCloneCloudNotFoundError extends Error {
13
- sourceEngramId;
14
- constructor(sourceEngramId) {
15
- super(`Engram "${sourceEngramId}" not found on Mikoshi`);
16
- this.sourceEngramId = sourceEngramId;
17
- this.name = "MikoshiCloneCloudNotFoundError";
18
- }
19
- }
20
- export class MikoshiClonePersonaMissingError extends Error {
21
- cloudEngramId;
22
- constructor(cloudEngramId) {
23
- super(`Remote Engram "${cloudEngramId}" is missing SOUL.md or IDENTITY.md`);
24
- this.cloudEngramId = cloudEngramId;
25
- this.name = "MikoshiClonePersonaMissingError";
26
- }
27
- }
28
- // ---------------------------------------------------------------------------
29
- // Usecase
30
- // ---------------------------------------------------------------------------
31
- export class MikoshiClone {
32
- localRepo;
33
- mikoshi;
34
- constructor(localRepo, mikoshi) {
35
- this.localRepo = localRepo;
36
- this.mikoshi = mikoshi;
37
- }
38
- /**
39
- * Clone a remote Engram from Mikoshi to local.
40
- * Fails if the local Engram already exists.
41
- */
42
- async execute(engramId) {
43
- // 1. ローカルに既に存在 → エラー
44
- const existing = await this.localRepo.get(engramId);
45
- if (existing) {
46
- throw new MikoshiCloneAlreadyExistsError(engramId);
47
- }
48
- // 2. クラウド検索
49
- const cloudEngram = await this.mikoshi.getEngramBySourceId(engramId);
50
- if (!cloudEngram)
51
- throw new MikoshiCloneCloudNotFoundError(engramId);
52
- // 3. Detail 取得 (persona content 込み)
53
- const detail = await this.mikoshi.getEngram(cloudEngram.id);
54
- const { soul, identity } = extractPersona(detail);
55
- if (!soul || !identity) {
56
- throw new MikoshiClonePersonaMissingError(cloudEngram.id);
57
- }
58
- // 4. ローカルに新規作成
59
- const now = new Date().toISOString();
60
- await this.localRepo.save({
61
- meta: {
62
- id: engramId,
63
- name: detail.name,
64
- description: detail.description ?? undefined,
65
- tags: detail.tags,
66
- createdAt: now,
67
- updatedAt: now,
68
- },
69
- files: {
70
- soul,
71
- identity,
72
- },
73
- });
74
- return {
75
- engramId,
76
- engramName: detail.name,
77
- cloudEngramId: cloudEngram.id,
78
- };
79
- }
80
- }
81
- // ---------------------------------------------------------------------------
82
- // Helpers
83
- // ---------------------------------------------------------------------------
84
- function extractPersona(detail) {
85
- let soul;
86
- let identity;
87
- for (const f of detail.personaFiles) {
88
- if (f.fileType === "SOUL")
89
- soul = f.content;
90
- if (f.fileType === "IDENTITY")
91
- identity = f.content;
92
- }
93
- return { soul, identity };
94
- }
@@ -1,2 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerExtractCommand(program: Command): void;
@@ -1,37 +0,0 @@
1
- import { LocalEngramRepository } from "../../../adapters/local/index.js";
2
- import { Extract, WorkspaceNotFoundError, WorkspaceEmptyError, AlreadyExtractedError, } from "../../../core/usecases/index.js";
3
- import { resolveEngramsPath, resolveOpenclawPath } from "../../../shared/config.js";
4
- export function registerExtractCommand(program) {
5
- program
6
- .command("extract")
7
- .description("Create a new Engram from an OpenClaw agent workspace")
8
- .option("-a, --agent <name>", "OpenClaw agent name to extract from (default: main)")
9
- .option("--name <name>", "Engram display name (defaults to agent name)")
10
- .option("--openclaw <dir>", "Override OpenClaw directory path (default: ~/.openclaw)")
11
- .option("-p, --path <dir>", "Override engrams directory path")
12
- .action(async (opts) => {
13
- const engramsPath = await resolveEngramsPath(opts.path);
14
- const openclawDir = await resolveOpenclawPath(opts.openclaw);
15
- const repo = new LocalEngramRepository(engramsPath);
16
- const extract = new Extract(repo);
17
- try {
18
- const agentName = opts.agent ?? "main";
19
- const result = await extract.execute(agentName, {
20
- name: opts.name,
21
- openclawDir,
22
- });
23
- console.log(`Extracted "${result.engramName}" from ${result.sourcePath}`);
24
- console.log(` Files read: ${result.filesRead.join(", ")}`);
25
- console.log(` Saved as Engram: ${result.engramId}`);
26
- }
27
- catch (err) {
28
- if (err instanceof WorkspaceNotFoundError ||
29
- err instanceof WorkspaceEmptyError ||
30
- err instanceof AlreadyExtractedError) {
31
- console.error(`Error: ${err.message}`);
32
- process.exit(1);
33
- }
34
- throw err;
35
- }
36
- });
37
- }
@@ -1,2 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerInjectCommand(program: Command): void;
@@ -1,34 +0,0 @@
1
- import { LocalEngramRepository } from "../../../adapters/local/index.js";
2
- import { Inject, InjectEngramNotFoundError, InjectWorkspaceNotFoundError, } from "../../../core/usecases/index.js";
3
- import { resolveEngramsPath, resolveOpenclawPath } from "../../../shared/config.js";
4
- export function registerInjectCommand(program) {
5
- program
6
- .command("inject")
7
- .description("Inject an Engram into an OpenClaw workspace")
8
- .requiredOption("-e, --engram <id>", "Engram ID to inject (= agent name)")
9
- .option("--to <agent>", "Inject into a different agent name")
10
- .option("--openclaw <dir>", "Override OpenClaw directory path (default: ~/.openclaw)")
11
- .option("-p, --path <dir>", "Override engrams directory path")
12
- .action(async (opts) => {
13
- const engramsPath = await resolveEngramsPath(opts.path);
14
- const openclawDir = await resolveOpenclawPath(opts.openclaw);
15
- const repo = new LocalEngramRepository(engramsPath);
16
- const inject = new Inject(repo);
17
- try {
18
- const result = await inject.execute(opts.engram, {
19
- to: opts.to,
20
- openclawDir,
21
- });
22
- console.log(`Injected "${result.engramName}" into ${result.targetPath}`);
23
- console.log(` Files written: ${result.filesWritten.join(", ")}`);
24
- }
25
- catch (err) {
26
- if (err instanceof InjectEngramNotFoundError ||
27
- err instanceof InjectWorkspaceNotFoundError) {
28
- console.error(`Error: ${err.message}`);
29
- process.exit(1);
30
- }
31
- throw err;
32
- }
33
- });
34
- }
@@ -1,2 +0,0 @@
1
- import type { Command } from "commander";
2
- export declare function registerSyncCommand(program: Command): void;
@@ -1,47 +0,0 @@
1
- import { LocalEngramRepository } from "../../../adapters/local/index.js";
2
- import { Sync, SyncOpenclawDirNotFoundError, } from "../../../core/usecases/index.js";
3
- import { resolveEngramsPath } from "../../../shared/config.js";
4
- export function registerSyncCommand(program) {
5
- program
6
- .command("sync")
7
- .description("Bidirectional memory sync between Relic Engrams and OpenClaw workspaces")
8
- .option("--openclaw <dir>", "Override OpenClaw directory path (default: ~/.openclaw)")
9
- .option("-p, --path <dir>", "Override engrams directory path")
10
- .action(async (opts) => {
11
- const engramsPath = await resolveEngramsPath(opts.path);
12
- const repo = new LocalEngramRepository(engramsPath);
13
- const sync = new Sync(repo, engramsPath);
14
- try {
15
- const result = await sync.execute(opts.openclaw);
16
- if (result.synced.length === 0 && result.skipped.length === 0) {
17
- console.log("No OpenClaw workspaces found.");
18
- return;
19
- }
20
- for (const s of result.synced) {
21
- const details = [];
22
- if (s.memoryFilesMerged > 0) {
23
- details.push(`${s.memoryFilesMerged} memory file(s)`);
24
- }
25
- if (s.memoryIndexMerged) {
26
- details.push("MEMORY.md");
27
- }
28
- if (details.length > 0) {
29
- console.log(` ${s.engramId}: merged ${details.join(", ")}`);
30
- }
31
- else {
32
- console.log(` ${s.engramId}: already in sync`);
33
- }
34
- }
35
- if (result.skipped.length > 0) {
36
- console.log(` Skipped (no matching Engram): ${result.skipped.join(", ")}`);
37
- }
38
- }
39
- catch (err) {
40
- if (err instanceof SyncOpenclawDirNotFoundError) {
41
- console.error(`Error: ${err.message}`);
42
- process.exit(1);
43
- }
44
- throw err;
45
- }
46
- });
47
- }
@@ -1,78 +0,0 @@
1
- /**
2
- * MemoryInbox — ファイルベースのメモリ受付口 + セッションログ
3
- *
4
- * LLMが inbox.md に追記すると、fs.watchで検知して処理する。
5
- * inbox.md は書き溜め式で、セッションを跨いで追記され続ける。
6
- * 処理済みエントリ数は inbox.cursor に永続化され、
7
- * クラッシュ後の再起動でも正確に未処理分だけを回収できる。
8
- *
9
- * エントリの種別:
10
- * - `[memory] ...` → memory/*.md に永続化される記憶
11
- * - タグ無し → inbox.md にログとして残るだけ(会話サマリー等)
12
- *
13
- * フォーマット:
14
- * 各エントリは `---` (前後に改行) で区切る。
15
- *
16
- * 例:
17
- * Discussed improving RELIC's memory system.
18
- * ---
19
- * Implemented inbox-based approach for cross-LLM persistence.
20
- * ---
21
- * [memory] User prefers Bun over Node.js for all TypeScript projects.
22
- * ---
23
- * [memory] Project RELIC uses clean architecture with Zod for validation.
24
- */
25
- export declare class MemoryInbox {
26
- private readonly engramId;
27
- private readonly engramsPath;
28
- private watcher;
29
- private processedCount;
30
- private processing;
31
- private memorySaved;
32
- private logCount;
33
- private savedEntries;
34
- readonly inboxPath: string;
35
- private readonly cursorPath;
36
- constructor(engramId: string, engramsPath: string);
37
- /**
38
- * Inboxを起動する。
39
- *
40
- * 1. cursorファイルから前回の処理済み位置を復元
41
- * 2. inbox.md の未処理エントリを回収(クラッシュ回復)
42
- * 3. fs.watch で監視開始
43
- */
44
- start(): Promise<MemoryInboxRecoveryResult>;
45
- /**
46
- * 監視を停止し、最終掃引を行う。
47
- * inbox.md はそのまま残す(書き溜め式)。
48
- */
49
- stop(): Promise<MemoryInboxResult>;
50
- /**
51
- * ファイル全体をパースし、未処理のエントリだけを処理する。
52
- *
53
- * - `[memory]` タグ付き → MemoryWrite で永続化
54
- * - タグ無し → カウントのみ(inbox.md にログとして残る)
55
- *
56
- * 処理成功ごとにカーソルを永続化するため、
57
- * 途中でクラッシュしても処理済み分は再処理されない。
58
- */
59
- private processNewEntries;
60
- private loadCursor;
61
- private saveCursor;
62
- }
63
- export interface MemoryInboxResult {
64
- /** memory/*.md に永続化されたエントリ数 */
65
- memories: number;
66
- /** ログとして記録されたエントリ数 */
67
- logs: number;
68
- /** 永続化されたメモリの内容 */
69
- entries: string[];
70
- }
71
- export interface MemoryInboxRecoveryResult {
72
- /** 回収されたメモリ数 */
73
- recoveredMemories: number;
74
- /** 回収されたログ数 */
75
- recoveredLogs: number;
76
- /** 回収されたメモリの内容 */
77
- entries: string[];
78
- }
@@ -1,168 +0,0 @@
1
- import { watch, existsSync, writeFileSync, readFileSync } from "node:fs";
2
- import { readFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { MemoryWrite } from "../core/usecases/memory-write.js";
5
- const INBOX_FILE = "inbox.md";
6
- const CURSOR_FILE = "inbox.cursor";
7
- const ENTRY_SEPARATOR = /\n---\n/;
8
- const MEMORY_TAG = /^\[memory\]\s*/i;
9
- /**
10
- * MemoryInbox — ファイルベースのメモリ受付口 + セッションログ
11
- *
12
- * LLMが inbox.md に追記すると、fs.watchで検知して処理する。
13
- * inbox.md は書き溜め式で、セッションを跨いで追記され続ける。
14
- * 処理済みエントリ数は inbox.cursor に永続化され、
15
- * クラッシュ後の再起動でも正確に未処理分だけを回収できる。
16
- *
17
- * エントリの種別:
18
- * - `[memory] ...` → memory/*.md に永続化される記憶
19
- * - タグ無し → inbox.md にログとして残るだけ(会話サマリー等)
20
- *
21
- * フォーマット:
22
- * 各エントリは `---` (前後に改行) で区切る。
23
- *
24
- * 例:
25
- * Discussed improving RELIC's memory system.
26
- * ---
27
- * Implemented inbox-based approach for cross-LLM persistence.
28
- * ---
29
- * [memory] User prefers Bun over Node.js for all TypeScript projects.
30
- * ---
31
- * [memory] Project RELIC uses clean architecture with Zod for validation.
32
- */
33
- export class MemoryInbox {
34
- engramId;
35
- engramsPath;
36
- watcher = null;
37
- processedCount = 0;
38
- processing = false;
39
- memorySaved = 0;
40
- logCount = 0;
41
- savedEntries = [];
42
- inboxPath;
43
- cursorPath;
44
- constructor(engramId, engramsPath) {
45
- this.engramId = engramId;
46
- this.engramsPath = engramsPath;
47
- const engramDir = join(engramsPath, engramId);
48
- this.inboxPath = join(engramDir, INBOX_FILE);
49
- this.cursorPath = join(engramDir, CURSOR_FILE);
50
- }
51
- /**
52
- * Inboxを起動する。
53
- *
54
- * 1. cursorファイルから前回の処理済み位置を復元
55
- * 2. inbox.md の未処理エントリを回収(クラッシュ回復)
56
- * 3. fs.watch で監視開始
57
- */
58
- async start() {
59
- if (!existsSync(this.inboxPath)) {
60
- writeFileSync(this.inboxPath, "", "utf-8");
61
- }
62
- this.processedCount = this.loadCursor();
63
- const recovered = await this.processNewEntries();
64
- this.watcher = watch(this.inboxPath, async (eventType) => {
65
- if (eventType === "change") {
66
- await this.processNewEntries();
67
- }
68
- });
69
- this.watcher.on("error", () => { });
70
- return {
71
- recoveredMemories: recovered.memories,
72
- recoveredLogs: recovered.logs,
73
- entries: recovered.savedEntries,
74
- };
75
- }
76
- /**
77
- * 監視を停止し、最終掃引を行う。
78
- * inbox.md はそのまま残す(書き溜め式)。
79
- */
80
- async stop() {
81
- if (this.watcher) {
82
- this.watcher.close();
83
- this.watcher = null;
84
- }
85
- await this.processNewEntries();
86
- return {
87
- memories: this.memorySaved,
88
- logs: this.logCount,
89
- entries: this.savedEntries,
90
- };
91
- }
92
- /**
93
- * ファイル全体をパースし、未処理のエントリだけを処理する。
94
- *
95
- * - `[memory]` タグ付き → MemoryWrite で永続化
96
- * - タグ無し → カウントのみ(inbox.md にログとして残る)
97
- *
98
- * 処理成功ごとにカーソルを永続化するため、
99
- * 途中でクラッシュしても処理済み分は再処理されない。
100
- */
101
- async processNewEntries() {
102
- if (this.processing)
103
- return { memories: 0, logs: 0, savedEntries: [] };
104
- this.processing = true;
105
- const result = { memories: 0, logs: 0, savedEntries: [] };
106
- try {
107
- if (!existsSync(this.inboxPath))
108
- return result;
109
- const fullContent = await readFile(this.inboxPath, "utf-8");
110
- if (!fullContent.trim())
111
- return result;
112
- const allEntries = fullContent
113
- .split(ENTRY_SEPARATOR)
114
- .map((e) => e.trim())
115
- .filter((e) => e.length > 0);
116
- const newEntries = allEntries.slice(this.processedCount);
117
- if (newEntries.length === 0)
118
- return result;
119
- const writer = new MemoryWrite(this.engramsPath);
120
- for (const raw of newEntries) {
121
- const isMemory = MEMORY_TAG.test(raw);
122
- if (isMemory) {
123
- const content = raw.replace(MEMORY_TAG, "").trim();
124
- try {
125
- await writer.execute(this.engramId, content);
126
- this.memorySaved++;
127
- this.savedEntries.push(content);
128
- result.memories++;
129
- result.savedEntries.push(content);
130
- }
131
- catch (err) {
132
- console.error(`[relic:inbox] Failed to save memory: ${err}`);
133
- }
134
- }
135
- else {
136
- this.logCount++;
137
- result.logs++;
138
- }
139
- this.processedCount++;
140
- this.saveCursor();
141
- }
142
- }
143
- finally {
144
- this.processing = false;
145
- }
146
- return result;
147
- }
148
- loadCursor() {
149
- if (!existsSync(this.cursorPath))
150
- return 0;
151
- try {
152
- const raw = readFileSync(this.cursorPath, "utf-8").trim();
153
- const n = parseInt(raw, 10);
154
- return Number.isNaN(n) ? 0 : n;
155
- }
156
- catch {
157
- return 0;
158
- }
159
- }
160
- saveCursor() {
161
- try {
162
- writeFileSync(this.cursorPath, String(this.processedCount), "utf-8");
163
- }
164
- catch {
165
- /* best effort */
166
- }
167
- }
168
- }
@@ -1,47 +0,0 @@
1
- /**
2
- * SessionRecorder — PTYストリームから会話履歴とメモリを記録する
3
- *
4
- * 役割:
5
- * 1. full_history.md に全会話を蓄積(ANSI除去済みテキスト)
6
- * 2. ストリーム中の [memory] タグを検出し memory/*.md に永続化
7
- *
8
- * full_history.md は無限に蓄積され続ける。セッションごとにヘッダーが挿入される。
9
- */
10
- export declare class SessionRecorder {
11
- private readonly engramId;
12
- private readonly engramsPath;
13
- readonly historyPath: string;
14
- private memoryBuffer;
15
- private memorySaved;
16
- private savedEntries;
17
- constructor(engramId: string, engramsPath: string);
18
- /**
19
- * セッション開始。ヘッダーを full_history.md に追記する。
20
- */
21
- start(shellName: string): void;
22
- /**
23
- * PTYストリームのデータを処理する。
24
- * spawnShellWithPty の onData コールバックから呼ぶ。
25
- *
26
- * - ANSI除去してfull_history.mdに追記
27
- * - [memory] タグを検出してバッファに溜める
28
- */
29
- onData(rawData: string): void;
30
- /**
31
- * セッション終了。残りのバッファを処理する。
32
- */
33
- stop(): Promise<SessionRecorderResult>;
34
- /**
35
- * memoryBuffer から完成した行を取り出し、[memory] タグを検出して永続化する。
36
- * final=true の場合は残りのバッファも全て処理する。
37
- */
38
- private flushMemoryBuffer;
39
- }
40
- export interface SessionRecorderResult {
41
- /** memory/*.md に永続化されたメモリ数 */
42
- memories: number;
43
- /** 永続化されたメモリの内容 */
44
- entries: string[];
45
- /** full_history.md のパス */
46
- historyPath: string;
47
- }