@ectplsm/relic 0.1.3 → 0.1.4

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 CHANGED
@@ -11,47 +11,9 @@
11
11
  /_/ |_/_____/_____/___/\____/
12
12
  ```
13
13
 
14
- **Inject AI personas into any coding CLI.**
14
+ **Inject a unified AI persona with persistent memory into any coding CLI.**
15
15
 
16
- Relic manages AI personalities (called **Engrams**) and injects them into coding assistants like Claude Code, Gemini CLI, Codex CLI. One persona, any shell.
17
-
18
- ```bash
19
- # Initialize Relic (creates ~/.relic/ with sample Engrams)
20
- relic init
21
-
22
- # Set a default Engram once
23
- relic config default-engram johnny
24
-
25
- # Launch Claude Code as Johnny — no flags needed
26
- relic claude
27
-
28
- # Or specify explicitly
29
- relic claude --engram motoko
30
- ```
31
-
32
- ## How It Works
33
-
34
- ```
35
- +--------------+ +--------------+ +--------------+
36
- | Mikoshi | | Relic | | Shell |
37
- | (backend) | | (injector) | | (AI CLI) |
38
- +--------------+ +--------------+ +--------------+
39
- | | |
40
- +---------+ compose & +---------+
41
- | Engram |------> inject ------------->|Construct|
42
- |(persona)| | (live) |
43
- +---------+ +---------+
44
- SOUL.md claude
45
- IDENTITY.md gemini
46
- MEMORY.md codex
47
- ...
48
- ```
49
-
50
- 1. **Engram** — A persona defined as a set of Markdown files (OpenClaw-compatible)
51
- 2. **Relic** — Reads the Engram, composes it into a prompt, and injects it into...
52
- 3. **Shell** — Any AI coding CLI. The persona takes over the session.
53
- 4. **Construct** — A live process where an Engram is loaded into a Shell. The running instance of a persona.
54
- 5. **Mikoshi** — Cloud backend where Engrams are stored and synced (planned).
16
+ Relic manages AI **Engrams** (memory + personality) and injects them into coding assistants like Claude Code, Codex CLI, Gemini CLI. One persona, any shell.
55
17
 
56
18
  ## Installation
57
19
 
@@ -74,14 +36,48 @@ relic show motoko
74
36
 
75
37
  # Launch a Shell (uses default Engram if --engram is omitted)
76
38
  relic claude
77
- relic gemini
78
39
  relic codex
40
+ relic gemini
79
41
 
80
42
  # Or specify explicitly
81
43
  relic claude --engram motoko
82
- relic gemini --engram johnny
44
+ relic codex --engram johnny
83
45
  ```
84
46
 
47
+ ## What `relic init` Creates
48
+
49
+ Running `relic init` creates `~/.relic/`, writes `config.json`, and seeds two sample Engrams under `~/.relic/engrams/`.
50
+
51
+ ```
52
+ ~/.relic/
53
+ ├── config.json
54
+ └── engrams/
55
+ ├── johnny/
56
+ │ ├── engram.json
57
+ │ ├── SOUL.md
58
+ │ ├── IDENTITY.md
59
+ │ └── memory/
60
+ │ └── YYYY-MM-DD.md
61
+ └── motoko/
62
+ ├── engram.json
63
+ ├── SOUL.md
64
+ ├── IDENTITY.md
65
+ └── memory/
66
+ └── YYYY-MM-DD.md
67
+ ```
68
+
69
+ - `config.json` stores global Relic settings such as `engramsPath`, `defaultEngram`, `openclawPath`, and `memoryWindowSize`.
70
+ - `engrams/<id>/` is one Engram workspace. This is where persona files and memory for that Engram live.
71
+ - `engram.json` stores metadata like the Engram's ID, display name, description, and tags.
72
+ - `SOUL.md` and `IDENTITY.md` define the persona itself.
73
+ - `memory/YYYY-MM-DD.md` stores dated distilled memory entries. `relic init` seeds an initial memory file for each sample Engram.
74
+
75
+ As you keep using an Engram, more files are added to the same workspace:
76
+
77
+ - `archive.md` is created inside `engrams/<id>/` when shell hooks start logging raw conversation turns.
78
+ - `MEMORY.md` can be created or extended when especially important distilled facts are promoted to long-term memory.
79
+ - `~/.relic/hooks/` and `~/.relic/gemini-system-default.md` are created later on first shell launch when hook registration or Gemini prompt caching is needed.
80
+
85
81
  ## Sample Engrams
86
82
 
87
83
  `relic init` seeds two ready-to-use Engrams:
@@ -110,13 +106,60 @@ Best for: system design, code review, debugging sessions, when precision matters
110
106
  relic claude --engram motoko
111
107
  ```
112
108
 
109
+ ## How It Works
110
+
111
+ ```
112
+ +--------------+ +--------------+ +--------------+
113
+ | Mikoshi | | Relic | | Shell |
114
+ | (backend) | | (injector) | | (AI CLI) |
115
+ +--------------+ +--------------+ +--------------+
116
+ ^ | |
117
+ | sync full Engram |
118
+ | | |
119
+ | compose & inject |
120
+ | v v
121
+ | +---------+ +---------+
122
+ +--------------| Engram |--------->|Construct|
123
+ |(persona)| | (live) |
124
+ +---------+ +---------+
125
+ SOUL.md claude / codex / gemini
126
+ IDENTITY.md |
127
+ MEMORY.md | hooks append logs
128
+ memory/*.md v
129
+ +-----------+
130
+ |archive.md |
131
+ | raw logs |
132
+ +-----------+
133
+ |
134
+ MCP recall | user-triggered
135
+ search/pending | distillation
136
+ v
137
+ +-----------+
138
+ | distilled |
139
+ |memory/*.md|
140
+ +-----------+
141
+ |
142
+ promote key
143
+ insights
144
+ v
145
+ MEMORY.md
146
+ ```
147
+
148
+ 1. **Engram** — A persona defined as a set of Markdown files (OpenClaw workspace-compatible)
149
+ 2. **Relic** — Reads the Engram, composes it into a prompt, and injects it into...
150
+ 3. **Shell** — Any AI coding CLI. The persona takes over the session.
151
+ 4. **Construct** — A live process where an Engram is loaded into a Shell. The running instance of a persona.
152
+ 5. **archive.md** — Raw conversation logs appended automatically by background hooks after each turn.
153
+ 6. **Memory Distillation** — The user triggers distillation; the Construct recalls pending archive entries via MCP, writes distilled insights to `memory/*.md`, and can promote especially important facts into `MEMORY.md`.
154
+ 7. **Mikoshi** — Cloud backend where the full Engram is stored and synced, including persona files plus distilled memory (planned).
155
+
113
156
  ## Supported Shells
114
157
 
115
158
  | Shell | Command | Injection Method |
116
159
  |-------|---------|-----------------|
117
160
  | [Claude Code](https://github.com/anthropics/claude-code) | `relic claude` | `--system-prompt` (direct override) |
118
- | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `relic gemini` | `GEMINI_SYSTEM_MD` (system prompt) |
119
161
  | [Codex CLI](https://github.com/openai/codex) | `relic codex` | `-c developer_instructions` (developer-role message) |
162
+ | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `relic gemini` | `GEMINI_SYSTEM_MD` (system prompt) |
120
163
 
121
164
  All shell commands support:
122
165
  - `--engram <id>` — Engram to inject (optional if `defaultEngram` is configured)
@@ -125,18 +168,61 @@ All shell commands support:
125
168
 
126
169
  Extra arguments are passed through to the underlying CLI.
127
170
 
171
+ ## Conversation Log Recording
172
+
173
+ Using each shell's `hook` mechanism, conversation content is appended to `archive.md` after every prompt and response.
174
+
175
+ The following hooks are used for each shell:
176
+
177
+ | Shell | Hook |
178
+ |-------|------|
179
+ | [Claude Code](https://github.com/anthropics/claude-code) | Stop hook |
180
+ | [Gemini CLI](https://github.com/google-gemini/gemini-cli) | AfterAgent hook |
181
+ | [Codex CLI](https://github.com/openai/codex) | Stop hook |
182
+
183
+ #### Claude Code
184
+
185
+ On the **first run** of `relic claude`, a one-time setup happens automatically:
186
+
187
+ - **Stop hook** — registers `~/.relic/hooks/claude-stop.js` in `~/.claude/settings.json` to log each conversation turn directly to the archive, without going through the LLM
188
+
189
+ #### Codex CLI
190
+
191
+ On the **first run** of `relic codex`, a one-time setup happens automatically:
192
+
193
+ - **Stop hook** — registers `~/.relic/hooks/codex-stop.js` in `~/.codex/hooks.json` to log each conversation turn directly to the archive, without going through the LLM
194
+
195
+ > **Note:** Codex hooks require the experimental feature flag `features.codex_hooks=true`. This is automatically enabled by `relic codex` on every launch via `-c features.codex_hooks=true`. If the unstable feature warning is distracting, add the following to `~/.codex/config.toml`:
196
+ >
197
+ > ```toml
198
+ > # Must be at the top level (not under any [section])
199
+ > suppress_unstable_features_warning = true
200
+ > ```
201
+
202
+ #### Gemini CLI
203
+
204
+ On the **first run** of `relic gemini`, two one-time setups happen automatically:
205
+
206
+ 1. **AfterAgent hook** — registers `~/.relic/hooks/gemini-after-agent.js` in `~/.gemini/settings.json` to log each conversation turn without going through the LLM
207
+ 2. **Default system prompt cache** — captures Gemini CLI's built-in system prompt to `~/.relic/gemini-system-default.md` via `GEMINI_WRITE_SYSTEM_MD`
208
+
209
+ The Engram persona is then appended to the cached default prompt and injected via `GEMINI_SYSTEM_MD` on every launch.
210
+
211
+
128
212
  ## MCP Server
129
213
 
130
214
  Relic's [MCP](https://modelcontextprotocol.io/) server is paired with CLI injection to handle memory recall.
131
- Session logs and memory entries are written automatically by a **background hook** — without going through the LLM. Memory recall, on the other hand, is performed via the MCP server.
215
+ Session logs and memory entries are written automatically by a **background hook** — without going through the LLM. Memory distillation and recall, on the other hand, is performed via the MCP server.
132
216
 
133
- ```
134
- relic xxx --engram johnny → injects persona into AI CLI
135
- relic-mcp (MCP server) → provides the Construct with memory recall
136
- Stop hook (Claude Code) → logs each turn directly to archive, bypassing the LLM
137
- AfterAgent hook (Gemini CLI) → logs each turn directly to archive, bypassing the LLM
138
- Stop hook (Codex CLI) → logs each turn directly to archive, bypassing the LLM
139
- ```
217
+ ### Available Tools
218
+
219
+ | Tool | Description |
220
+ |------|-------------|
221
+ | `relic_archive_search` | Search the Engram's raw archive by keyword (newest-first) |
222
+ | `relic_archive_pending` | Get un-distilled archive entries since the last distillation (up to 30) |
223
+ | `relic_memory_write` | Write distilled memory to `memory/*.md`, optionally append to `MEMORY.md`, and advance the archive cursor |
224
+
225
+ Session logs are written automatically by background hooks (Stop hook for Claude Code and Codex CLI, AfterAgent hook for Gemini CLI). Memory distillation is triggered by the user — ask the Construct to "organize memories" and it will fetch pending entries, distill key insights, and write them to `memory/*.md`. Especially important facts can be promoted to `MEMORY.md` (long-term memory included in every session) via the `long_term` parameter.
140
226
 
141
227
  ### Setup
142
228
 
@@ -163,9 +249,11 @@ To suppress confirmation dialogs and auto-approve Relic tools across all project
163
249
 
164
250
  > **Note:** The "Always allow" option in the confirmation dialog saves to `~/.claude.json` (project-scoped cache) — it does **not** persist globally. For global auto-approval, `~/.claude/settings.json` is the right place.
165
251
 
166
- On the **first run** of `relic claude`, a one-time setup happens automatically:
252
+ #### Codex CLI
167
253
 
168
- - **Stop hook** — registers `~/.relic/hooks/claude-stop.js` in `~/.claude/settings.json` to log each conversation turn directly to the archive, without going through the LLM
254
+ ```bash
255
+ codex mcp add relic -- relic-mcp
256
+ ```
169
257
 
170
258
  #### Gemini CLI
171
259
 
@@ -184,40 +272,6 @@ Add to `~/.gemini/settings.json`:
184
272
 
185
273
  > **Note:** `trust: true` is required to suppress confirmation dialogs for Relic tools. Without it, dialogs will appear on every call even if you select "Allow for all future sessions" — this is a known bug in Gemini CLI where the tool name is saved in the wrong format, causing the saved rule to never match.
186
274
 
187
- On the **first run** of `relic gemini`, two one-time setups happen automatically:
188
-
189
- 1. **AfterAgent hook** — registers `~/.relic/hooks/gemini-after-agent.js` in `~/.gemini/settings.json` to log each conversation turn without going through the LLM
190
- 2. **Default system prompt cache** — captures Gemini CLI's built-in system prompt to `~/.relic/gemini-system-default.md` via `GEMINI_WRITE_SYSTEM_MD`
191
-
192
- The Engram persona is then appended to the cached default prompt and injected via `GEMINI_SYSTEM_MD` on every launch.
193
-
194
- #### Codex CLI
195
-
196
- ```bash
197
- codex mcp add relic -- relic-mcp
198
- ```
199
-
200
- On the **first run** of `relic codex`, a one-time setup happens automatically:
201
-
202
- - **Stop hook** — registers `~/.relic/hooks/codex-stop.js` in `~/.codex/hooks.json` to log each conversation turn directly to the archive, without going through the LLM
203
-
204
- > **Note:** Codex hooks require the experimental feature flag `features.codex_hooks=true`. This is automatically enabled by `relic codex` on every launch via `-c features.codex_hooks=true`. If the unstable feature warning is distracting, add the following to `~/.codex/config.toml`:
205
- >
206
- > ```toml
207
- > # Must be at the top level (not under any [section])
208
- > suppress_unstable_features_warning = true
209
- > ```
210
-
211
- ### Available Tools
212
-
213
- | Tool | Description |
214
- |------|-------------|
215
- | `relic_archive_search` | Search the Engram's raw archive by keyword (newest-first) |
216
- | `relic_archive_pending` | Get un-distilled archive entries since the last distillation (up to 30) |
217
- | `relic_memory_write` | Write distilled memory to `memory/*.md`, optionally append to `MEMORY.md`, and advance the archive cursor |
218
-
219
- Session logs are written automatically by background hooks (Stop hook for Claude Code and Codex CLI, AfterAgent hook for Gemini CLI). Memory distillation is triggered by the user — ask the Construct to "organize memories" and it will fetch pending entries, distill key insights, and write them to `memory/*.md`. Especially important facts can be promoted to `MEMORY.md` (long-term memory included in every session) via the `long_term` parameter.
220
-
221
275
  ## OpenClaw Integration
222
276
 
223
277
  Relic Engrams are fully compatible with [OpenClaw](https://github.com/openclaw/openclaw) workspaces. They are mapped using a simple convention: Agent Name = Engram ID.
@@ -392,25 +446,6 @@ After creating the directory, set it as default:
392
446
  relic config default-engram your-persona
393
447
  ```
394
448
 
395
- ## Architecture
396
-
397
- Clean Architecture with dependency inversion:
398
-
399
- ```
400
- src/
401
- ├── core/ # Business logic (no external deps except Zod)
402
- │ ├── entities/ # Engram, Construct domain models
403
- │ ├── usecases/ # Summon, ListEngrams, Init
404
- │ └── ports/ # Abstract interfaces (EngramRepository, ShellLauncher)
405
- ├── adapters/ # Concrete implementations
406
- │ ├── local/ # Local filesystem EngramRepository
407
- │ └── shells/ # Claude, Gemini, Codex launchers
408
- ├── interfaces/ # Entry points
409
- │ ├── cli/ # Commander-based CLI
410
- │ └── mcp/ # MCP Server (stdio transport)
411
- └── shared/ # Engram composer, config management
412
- ```
413
-
414
449
  ## Domain Glossary
415
450
 
416
451
  | Term | Role | Description |
@@ -1,8 +1,11 @@
1
1
  export declare const CLAUDE_HOOK_SCRIPT_PATH: string;
2
2
  /**
3
- * Claude Code の Stop フックをセットアップする。
4
- * - ~/.relic/hooks/claude-stop.js を生成
5
- * - ~/.claude/settings.json に Stop フックを登録
3
+ * フックスクリプトを最新の内容で書き出す。
4
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
5
+ */
6
+ export declare function writeClaudeHookScript(): void;
7
+ /**
8
+ * Claude Code の Stop フックを settings.json に登録する。
6
9
  * 既にセットアップ済みの場合はスキップ。
7
10
  */
8
11
  export declare function setupClaudeHook(): void;
@@ -16,8 +16,8 @@ const HOOK_SCRIPT = `#!/usr/bin/env node
16
16
  // Relic Stop hook for Claude Code
17
17
  // Automatically logs each conversation turn to the Engram archive.
18
18
  // Receives Stop hook JSON on stdin.
19
- const { appendFileSync, existsSync, readFileSync } = require("node:fs");
20
- const { join } = require("node:path");
19
+ const { appendFileSync, existsSync, mkdirSync, readFileSync } = require("node:fs");
20
+ const { join, dirname } = require("node:path");
21
21
  const { homedir } = require("node:os");
22
22
 
23
23
  let raw = "";
@@ -35,7 +35,7 @@ process.stdin.on("end", () => {
35
35
  if (!transcriptPath || !existsSync(transcriptPath)) process.exit(0);
36
36
 
37
37
  const archivePath = join(homedir(), ".relic", "engrams", engramId, "archive.md");
38
- if (!existsSync(archivePath)) process.exit(0);
38
+ mkdirSync(dirname(archivePath), { recursive: true });
39
39
 
40
40
  // transcript.jsonl を読んで最後のユーザー入力とアシスタント応答を取り出す
41
41
  const lines = readFileSync(transcriptPath, "utf-8")
@@ -99,16 +99,19 @@ process.stdin.on("end", () => {
99
99
  });
100
100
  `;
101
101
  /**
102
- * Claude Code の Stop フックをセットアップする。
103
- * - ~/.relic/hooks/claude-stop.js を生成
104
- * - ~/.claude/settings.json に Stop フックを登録
105
- * 既にセットアップ済みの場合はスキップ。
102
+ * フックスクリプトを最新の内容で書き出す。
103
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
106
104
  */
107
- export function setupClaudeHook() {
108
- // 1. フックスクリプトを生成
105
+ export function writeClaudeHookScript() {
109
106
  mkdirSync(HOOKS_DIR, { recursive: true });
110
107
  writeFileSync(CLAUDE_HOOK_SCRIPT_PATH, HOOK_SCRIPT, { encoding: "utf-8", mode: 0o755 });
111
- // 2. ~/.claude/settings.json に Stop フックを登録
108
+ }
109
+ /**
110
+ * Claude Code の Stop フックを settings.json に登録する。
111
+ * 既にセットアップ済みの場合はスキップ。
112
+ */
113
+ export function setupClaudeHook() {
114
+ // ~/.claude/settings.json に Stop フックを登録
112
115
  const claudeDir = join(homedir(), ".claude");
113
116
  mkdirSync(claudeDir, { recursive: true });
114
117
  let settings = {};
@@ -1,7 +1,7 @@
1
1
  import { exec } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  import { spawnShell } from "./spawn-shell.js";
4
- import { setupClaudeHook, isClaudeHookSetup } from "./claude-hook.js";
4
+ import { setupClaudeHook, isClaudeHookSetup, writeClaudeHookScript } from "./claude-hook.js";
5
5
  const execAsync = promisify(exec);
6
6
  /**
7
7
  * Claude Code CLI アダプター
@@ -27,7 +27,9 @@ export class ClaudeShell {
27
27
  }
28
28
  }
29
29
  async launch(prompt, options) {
30
- // Stop フックを初回のみセットアップ
30
+ // フックスクリプトを毎回最新に更新
31
+ writeClaudeHookScript();
32
+ // settings.json への登録は初回のみ
31
33
  if (!isClaudeHookSetup()) {
32
34
  console.log("Setting up Claude Code Stop hook (first run only)...");
33
35
  setupClaudeHook();
@@ -1,8 +1,11 @@
1
1
  export declare const CODEX_HOOK_SCRIPT_PATH: string;
2
2
  /**
3
- * Codex CLI の Stop フックをセットアップする。
4
- * - ~/.relic/hooks/codex-stop.js を生成
5
- * - ~/.codex/hooks.json に Stop フックを登録
3
+ * フックスクリプトを最新の内容で書き出す。
4
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
5
+ */
6
+ export declare function writeCodexHookScript(): void;
7
+ /**
8
+ * Codex CLI の Stop フックを settings.json に登録する。
6
9
  * 既にセットアップ済みの場合はスキップ。
7
10
  */
8
11
  export declare function setupCodexHook(): void;
@@ -17,8 +17,8 @@ const HOOK_SCRIPT = `#!/usr/bin/env node
17
17
  // Relic Stop hook for Codex CLI
18
18
  // Automatically logs each conversation turn to the Engram archive.
19
19
  // Receives Stop hook JSON on stdin.
20
- const { appendFileSync, existsSync, readFileSync } = require("node:fs");
21
- const { join } = require("node:path");
20
+ const { appendFileSync, existsSync, mkdirSync, readFileSync } = require("node:fs");
21
+ const { join, dirname } = require("node:path");
22
22
  const { homedir } = require("node:os");
23
23
 
24
24
  let raw = "";
@@ -31,7 +31,7 @@ process.stdin.on("end", () => {
31
31
  if (!engramId) process.exit(0);
32
32
 
33
33
  const archivePath = join(homedir(), ".relic", "engrams", engramId, "archive.md");
34
- if (!existsSync(archivePath)) process.exit(0);
34
+ mkdirSync(dirname(archivePath), { recursive: true });
35
35
 
36
36
  // Codex Stop hook は last_assistant_message を直接提供する
37
37
  const lastResponse = (input.last_assistant_message || "").trim();
@@ -80,16 +80,19 @@ process.stdin.on("end", () => {
80
80
  });
81
81
  `;
82
82
  /**
83
- * Codex CLI の Stop フックをセットアップする。
84
- * - ~/.relic/hooks/codex-stop.js を生成
85
- * - ~/.codex/hooks.json に Stop フックを登録
86
- * 既にセットアップ済みの場合はスキップ。
83
+ * フックスクリプトを最新の内容で書き出す。
84
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
87
85
  */
88
- export function setupCodexHook() {
89
- // 1. フックスクリプトを生成
86
+ export function writeCodexHookScript() {
90
87
  mkdirSync(HOOKS_DIR, { recursive: true });
91
88
  writeFileSync(CODEX_HOOK_SCRIPT_PATH, HOOK_SCRIPT, { encoding: "utf-8", mode: 0o755 });
92
- // 2. ~/.codex/hooks.json に Stop フックを登録
89
+ }
90
+ /**
91
+ * Codex CLI の Stop フックを settings.json に登録する。
92
+ * 既にセットアップ済みの場合はスキップ。
93
+ */
94
+ export function setupCodexHook() {
95
+ // ~/.codex/hooks.json に Stop フックを登録
93
96
  const codexDir = join(homedir(), ".codex");
94
97
  mkdirSync(codexDir, { recursive: true });
95
98
  let hooksConfig = {};
@@ -2,7 +2,7 @@ import { exec } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  import { spawnShell } from "./spawn-shell.js";
4
4
  import { wrapWithOverride } from "./override-preamble.js";
5
- import { setupCodexHook, isCodexHookSetup } from "./codex-hook.js";
5
+ import { setupCodexHook, isCodexHookSetup, writeCodexHookScript } from "./codex-hook.js";
6
6
  const execAsync = promisify(exec);
7
7
  /**
8
8
  * Codex CLI アダプター
@@ -29,7 +29,9 @@ export class CodexShell {
29
29
  }
30
30
  }
31
31
  async launch(prompt, options) {
32
- // Stop フックを初回のみセットアップ
32
+ // フックスクリプトを毎回最新に更新
33
+ writeCodexHookScript();
34
+ // hooks.json への登録は初回のみ
33
35
  if (!isCodexHookSetup()) {
34
36
  console.log("Setting up Codex CLI Stop hook (first run only)...");
35
37
  setupCodexHook();
@@ -1,8 +1,11 @@
1
1
  export declare const GEMINI_HOOK_SCRIPT_PATH: string;
2
2
  /**
3
- * Gemini CLI の AfterAgent フックをセットアップする。
4
- * - ~/.relic/hooks/gemini-after-agent.js を生成
5
- * - ~/.gemini/settings.json に AfterAgent フックを登録
3
+ * フックスクリプトを最新の内容で書き出す。
4
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
5
+ */
6
+ export declare function writeGeminiHookScript(): void;
7
+ /**
8
+ * Gemini CLI の AfterAgent フックを settings.json に登録する。
6
9
  * 既にセットアップ済みの場合はスキップ。
7
10
  */
8
11
  export declare function setupGeminiHook(): void;
@@ -15,8 +15,8 @@ const HOOK_SCRIPT = `#!/usr/bin/env node
15
15
  // Relic AfterAgent hook for Gemini CLI
16
16
  // Automatically logs each conversation turn to the Engram archive.
17
17
  // Receives AfterAgentInput JSON on stdin.
18
- const { appendFileSync, existsSync } = require("node:fs");
19
- const { join } = require("node:path");
18
+ const { appendFileSync, existsSync, mkdirSync } = require("node:fs");
19
+ const { join, dirname } = require("node:path");
20
20
  const { homedir } = require("node:os");
21
21
 
22
22
  let raw = "";
@@ -33,7 +33,7 @@ process.stdin.on("end", () => {
33
33
  if (!prompt && !response) process.exit(0);
34
34
 
35
35
  const archivePath = join(homedir(), ".relic", "engrams", engramId, "archive.md");
36
- if (!existsSync(archivePath)) process.exit(0);
36
+ mkdirSync(dirname(archivePath), { recursive: true });
37
37
 
38
38
  const date = new Date().toISOString().split("T")[0];
39
39
  const summary = prompt.slice(0, 80).replace(/\\n/g, " ");
@@ -46,16 +46,19 @@ process.stdin.on("end", () => {
46
46
  });
47
47
  `;
48
48
  /**
49
- * Gemini CLI の AfterAgent フックをセットアップする。
50
- * - ~/.relic/hooks/gemini-after-agent.js を生成
51
- * - ~/.gemini/settings.json に AfterAgent フックを登録
52
- * 既にセットアップ済みの場合はスキップ。
49
+ * フックスクリプトを最新の内容で書き出す。
50
+ * 毎回呼ばれ、ソース変更がデプロイされることを保証する。
53
51
  */
54
- export function setupGeminiHook() {
55
- // 1. フックスクリプトを生成
52
+ export function writeGeminiHookScript() {
56
53
  mkdirSync(HOOKS_DIR, { recursive: true });
57
54
  writeFileSync(GEMINI_HOOK_SCRIPT_PATH, HOOK_SCRIPT, { encoding: "utf-8", mode: 0o755 });
58
- // 2. ~/.gemini/settings.json にフックを登録
55
+ }
56
+ /**
57
+ * Gemini CLI の AfterAgent フックを settings.json に登録する。
58
+ * 既にセットアップ済みの場合はスキップ。
59
+ */
60
+ export function setupGeminiHook() {
61
+ // ~/.gemini/settings.json にフックを登録
59
62
  const geminiDir = join(homedir(), ".gemini");
60
63
  mkdirSync(geminiDir, { recursive: true });
61
64
  let settings = {};
@@ -5,7 +5,7 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync
5
5
  import { join } from "node:path";
6
6
  import { homedir, tmpdir } from "node:os";
7
7
  import { spawnShell, writeTempPrompt } from "./spawn-shell.js";
8
- import { setupGeminiHook, isGeminiHookSetup } from "./gemini-hook.js";
8
+ import { setupGeminiHook, isGeminiHookSetup, writeGeminiHookScript } from "./gemini-hook.js";
9
9
  const execAsync = promisify(exec);
10
10
  const RELIC_DIR = join(homedir(), ".relic");
11
11
  const GEMINI_DEFAULT_CACHE = join(RELIC_DIR, "gemini-system-default.md");
@@ -97,7 +97,9 @@ export class GeminiShell {
97
97
  }
98
98
  }
99
99
  async launch(prompt, options) {
100
- // 1. AfterAgent フックを初回のみセットアップ
100
+ // 1. フックスクリプトを毎回最新に更新
101
+ writeGeminiHookScript();
102
+ // settings.json への登録は初回のみ
101
103
  if (!isGeminiHookSetup()) {
102
104
  console.log("Setting up Gemini AfterAgent hook (first run only)...");
103
105
  setupGeminiHook();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ectplsm/relic",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "PROJECT RELIC — Engram injection system for AI constructs",
5
5
  "license": "MIT",
6
6
  "repository": {