@eltonssouza/development-utility-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/analyst.md +198 -0
- package/.claude/agents/backend-developer.md +126 -0
- package/.claude/agents/brain-keeper.md +229 -0
- package/.claude/agents/code-reviewer.md +181 -0
- package/.claude/agents/database-engineer.md +94 -0
- package/.claude/agents/devops-engineer.md +141 -0
- package/.claude/agents/frontend-developer.md +97 -0
- package/.claude/agents/gate-keeper.md +118 -0
- package/.claude/agents/migrator.md +291 -0
- package/.claude/agents/mobile-developer.md +80 -0
- package/.claude/agents/n8n-specialist.md +94 -0
- package/.claude/agents/product-owner.md +115 -0
- package/.claude/agents/qa-engineer.md +232 -0
- package/.claude/agents/release-engineer.md +204 -0
- package/.claude/agents/scaffold.md +87 -0
- package/.claude/agents/security-engineer.md +199 -0
- package/.claude/agents/sprint-runner.md +44 -0
- package/.claude/agents/stack-resolver.md +84 -0
- package/.claude/agents/tech-lead.md +182 -0
- package/.claude/agents/update-template.md +54 -0
- package/.claude/agents/ux-designer.md +118 -0
- package/.claude/settings.json +44 -0
- package/.claude/skills/README.md +332 -0
- package/.claude/skills/active-project/SKILL.md +129 -0
- package/.claude/skills/api-integration-test/SKILL.md +64 -0
- package/.claude/skills/auto-test-guard/SKILL.md +237 -0
- package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
- package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
- package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
- package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
- package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
- package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
- package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
- package/.claude/skills/brain-keeper/SKILL.md +60 -0
- package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
- package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
- package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
- package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
- package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
- package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
- package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
- package/.claude/skills/brain-keeper/templates/README.md +51 -0
- package/.claude/skills/brain-keeper/templates/adr.md +40 -0
- package/.claude/skills/brain-keeper/templates/bug.md +35 -0
- package/.claude/skills/brain-keeper/templates/daily.md +38 -0
- package/.claude/skills/brain-keeper/templates/feature.md +62 -0
- package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
- package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
- package/.claude/skills/caveman/SKILL.md +187 -0
- package/.claude/skills/create-stack-pack/SKILL.md +281 -0
- package/.claude/skills/grill-me/SKILL.md +79 -0
- package/.claude/skills/honcho-memory/SKILL.md +207 -0
- package/.claude/skills/honcho-memory/docs/api-endpoints-verified.md +75 -0
- package/.claude/skills/honcho-memory/hooks/on-prompt-submit.js +221 -0
- package/.claude/skills/honcho-memory/hooks/on-stop.js +193 -0
- package/.claude/skills/honcho-memory/lib/honcho-client.js +363 -0
- package/.claude/skills/honcho-memory/lib/memory-injector.js +93 -0
- package/.claude/skills/honcho-memory/package.json +32 -0
- package/.claude/skills/honcho-memory/scripts/cli.js +370 -0
- package/.claude/skills/honcho-memory/scripts/setup.js +109 -0
- package/.claude/skills/honcho-memory/tests/t001-api-endpoints-verified.test.js +89 -0
- package/.claude/skills/honcho-memory/tests/t002-structure.test.js +97 -0
- package/.claude/skills/honcho-memory/tests/t003-honcho-client.test.js +162 -0
- package/.claude/skills/honcho-memory/tests/t004-soft-delete.test.js +259 -0
- package/.claude/skills/honcho-memory/tests/t005-memory-injector.test.js +175 -0
- package/.claude/skills/honcho-memory/tests/t006-on-prompt-submit.test.js +215 -0
- package/.claude/skills/honcho-memory/tests/t007-on-stop.test.js +165 -0
- package/.claude/skills/honcho-memory/tests/t008-cli.test.js +214 -0
- package/.claude/skills/honcho-memory/tests/t009-setup.test.js +232 -0
- package/.claude/skills/honcho-memory/tests/t010-skill-md.test.js +114 -0
- package/.claude/skills/honcho-memory/tests/t011-settings-hooks.test.js +105 -0
- package/.claude/skills/honcho-memory/tests/t012-docs-update.test.js +106 -0
- package/.claude/skills/honcho-memory/tests/t013-smoke-e2e.test.js +90 -0
- package/.claude/skills/pair-debug/SKILL.md +288 -0
- package/.claude/skills/prd-ready-check/SKILL.md +58 -0
- package/.claude/skills/project-manager/SKILL.md +167 -0
- package/.claude/skills/quality-standards/SKILL.md +201 -0
- package/.claude/skills/quick-feature/SKILL.md +264 -0
- package/.claude/skills/run-sprint/SKILL.md +342 -0
- package/.claude/skills/scaffold/SKILL.md +58 -0
- package/.claude/skills/stack-discovery/SKILL.md +159 -0
- package/.claude/skills/test-coverage-auditor/SKILL.md +59 -0
- package/.claude/skills/to-issues/SKILL.md +163 -0
- package/.claude/skills/to-prd/SKILL.md +130 -0
- package/.claude/skills/update-template/SKILL.md +254 -0
- package/.claude/stacks/CODEOWNERS +30 -0
- package/.claude/stacks/README.md +88 -0
- package/.claude/stacks/_template.md +116 -0
- package/.claude/stacks/java/spring-boot-3.md +376 -0
- package/.claude/stacks/java/spring-boot-4.md +438 -0
- package/.claude/stacks/typescript/angular-18.md +420 -0
- package/.claude/stacks/typescript/angular-19.md +397 -0
- package/.claude/stacks/typescript/angular-21.md +494 -0
- package/CLAUDE.md +453 -0
- package/README.md +391 -0
- package/bin/cli.js +773 -0
- package/bin/lib/backup.js +62 -0
- package/bin/lib/detect-stack.js +476 -0
- package/bin/lib/help.js +233 -0
- package/bin/lib/identity.js +108 -0
- package/bin/lib/local-dir.js +69 -0
- package/bin/lib/manifest.js +236 -0
- package/bin/lib/sync-all.js +394 -0
- package/bin/lib/version-check.js +398 -0
- package/dashboard/db.js +199 -0
- package/dashboard/package.json +22 -0
- package/dashboard/public/app.js +709 -0
- package/dashboard/public/content/docs/agents-reference.en.md +911 -0
- package/dashboard/public/content/docs/architecture-overview.en.md +260 -0
- package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
- package/dashboard/public/content/docs/git-flow.en.md +525 -0
- package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
- package/dashboard/public/content/docs/hooks-reference.en.md +420 -0
- package/dashboard/public/content/docs/pipeline.en.md +400 -0
- package/dashboard/public/content/docs/quality-gate.en.md +315 -0
- package/dashboard/public/content/docs/skills-reference.en.md +500 -0
- package/dashboard/public/content/docs/stack-rules.en.md +362 -0
- package/dashboard/public/content/docs/troubleshooting.en.md +637 -0
- package/dashboard/public/content/manifest.json +102 -0
- package/dashboard/public/content/manual/backend.en.md +1138 -0
- package/dashboard/public/content/manual/existing-project.en.md +831 -0
- package/dashboard/public/content/manual/frontend.en.md +1065 -0
- package/dashboard/public/content/manual/fullstack.en.md +1508 -0
- package/dashboard/public/content/manual/mobile.en.md +866 -0
- package/dashboard/public/index.html +108 -0
- package/dashboard/public/style.css +610 -0
- package/dashboard/public/vendor/marked.min.js +69 -0
- package/dashboard/rtk.js +143 -0
- package/dashboard/server-app.js +403 -0
- package/dashboard/server.js +104 -0
- package/dashboard/test/sprint1.test.js +406 -0
- package/dashboard/test/sprint2.test.js +571 -0
- package/dashboard/test/sprint3.test.js +560 -0
- package/package.json +33 -0
- package/scripts/hooks/subagent-telemetry.sh +14 -0
- package/scripts/hooks/telemetry-writer.js +250 -0
- package/scripts/latest-versions.json +56 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: honcho-memory
|
|
3
|
+
description: |
|
|
4
|
+
Persistent cross-session memory for Claude Code via Honcho v3 self-hosted.
|
|
5
|
+
Triggers on: "honcho memory", "memória honcho", "honcho skill",
|
|
6
|
+
"lembra que", "remember that", "memoriza", "memorize this",
|
|
7
|
+
"never do", "always do", "never use", "always use",
|
|
8
|
+
"/honcho save", "/honcho search", "/honcho list",
|
|
9
|
+
"/honcho forget", "/honcho status", "/honcho setup",
|
|
10
|
+
"save memory", "search memory", "list memories",
|
|
11
|
+
"forget memory", "honcho status", "honcho setup",
|
|
12
|
+
"memória persistente", "persistent memory", "cross-session memory".
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# honcho-memory
|
|
16
|
+
|
|
17
|
+
Persistent cross-session memory for Claude Code backed by **Honcho v3 self-hosted**.
|
|
18
|
+
|
|
19
|
+
Memories survive between sessions. Relevant memories are injected automatically
|
|
20
|
+
into every prompt via the `[HONCHO MEMORY]` block before Claude Code processes them.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Overview
|
|
25
|
+
|
|
26
|
+
The skill integrates Honcho v3 as a semantic memory backend. On every `UserPromptSubmit`
|
|
27
|
+
hook, the skill:
|
|
28
|
+
|
|
29
|
+
1. Detects explicit memory triggers ("lembra que", "remember that", "memoriza", "never ...", "always ...").
|
|
30
|
+
2. Saves any explicit memory **before** any search (BR-001).
|
|
31
|
+
3. Executes hybrid search in `Promise.all`:
|
|
32
|
+
- **Peer-scoped** (`POST /v3/workspaces/{ws}/peers/{peer}/search`) — retrieves `explicit`
|
|
33
|
+
and `inferred` memories, cross-project preferences.
|
|
34
|
+
- **Session-scoped** (`POST /v3/workspaces/{ws}/sessions/{sessionId}/messages/list`) — retrieves
|
|
35
|
+
`project-context` memories for the current directory.
|
|
36
|
+
4. Merges results by relevance, caps at `topN` items and 2,000 characters.
|
|
37
|
+
5. Injects the `[HONCHO MEMORY]...[/HONCHO MEMORY]` block into stdout (system prompt extension).
|
|
38
|
+
|
|
39
|
+
On `Stop`, the hook saves the active feature/sprint context as `project-context`.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Subcommands
|
|
44
|
+
|
|
45
|
+
All subcommands are available via the CLI:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
bun run .claude/skills/honcho-memory/scripts/cli.js <subcommand> [args]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Subcommand | Description |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `/honcho save <text>` | Save an explicit memory. Prints the saved message ID. |
|
|
54
|
+
| `/honcho search <query>` | Semantic search — returns top-N relevant memories (excludes soft-deleted). |
|
|
55
|
+
| `/honcho list` | List all memories in the current session (excludes soft-deleted). |
|
|
56
|
+
| `/honcho forget <id>` | Soft-delete a memory via `PUT /v3/workspaces/{ws}/sessions/{sessionId}/messages/{id}` with `{ "metadata": { "deleted": true } }`. Note: uses PUT, NOT DELETE — this is a soft-delete. Calling `forget` without an ID returns exit code 1. |
|
|
57
|
+
| `/honcho status` | Show connection status (OK/FAIL), memory count, config version, `enabled`, `inferenceEnabled` flags. |
|
|
58
|
+
| `/honcho setup` | Interactive wizard: verifies connection, migrates `memory/*.md` to Honcho with backup. |
|
|
59
|
+
|
|
60
|
+
### forget — soft-delete via PUT
|
|
61
|
+
|
|
62
|
+
`forget <id>` never calls HTTP DELETE. It calls:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
PUT /v3/workspaces/{ws}/sessions/{sessionId}/messages/{id}
|
|
66
|
+
Body: { "metadata": { "deleted": true } }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This is a **soft-delete** — the record is preserved in the database but excluded from
|
|
70
|
+
all future list/search results. The CLI stdout contains `"method": "PUT"` to confirm.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Automatic triggers
|
|
75
|
+
|
|
76
|
+
The following patterns in a user prompt trigger **immediate explicit save** before any search:
|
|
77
|
+
|
|
78
|
+
| Pattern | Example |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `lembra que` | "lembra que prefiro records imutáveis em DTOs Java" |
|
|
81
|
+
| `remember that` | "remember that I prefer immutable records" |
|
|
82
|
+
| `memoriza` | "memoriza: usar OnPush em todos os componentes Angular" |
|
|
83
|
+
| `never ...` | "never use var in TypeScript" |
|
|
84
|
+
| `always ...` | "always add JSDoc to public methods" |
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## [HONCHO MEMORY] block
|
|
89
|
+
|
|
90
|
+
When memories are available, the following block is injected into the system prompt extension:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[HONCHO MEMORY]
|
|
94
|
+
type: explicit | project: my-project | 2026-05-26T10:00:00Z
|
|
95
|
+
Prefer immutable records for DTOs in Java
|
|
96
|
+
|
|
97
|
+
type: project-context | project: development-utility-kit | 2026-05-26T09:00:00Z
|
|
98
|
+
Active feature: honcho-memory-skill Sprint 3
|
|
99
|
+
[/HONCHO MEMORY]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The block is limited to `topN` memories (default: 5) and 2,000 characters total.
|
|
103
|
+
Both opening and closing tags (`[HONCHO MEMORY]` / `[/HONCHO MEMORY]`) are always present.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Graceful degradation
|
|
108
|
+
|
|
109
|
+
When Honcho is unavailable (network timeout, 5xx, DNS failure):
|
|
110
|
+
|
|
111
|
+
- The hook aborts after `timeoutMs` ms (default: 450ms).
|
|
112
|
+
- A `HONCHO_WARN: <reason>` message is written to **stderr**.
|
|
113
|
+
- An **empty string** is written to stdout.
|
|
114
|
+
- Exit code is **0** — Claude Code proceeds normally without memory.
|
|
115
|
+
|
|
116
|
+
This ensures the skill **never blocks** the main workflow. Degradation is graceful.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Configuration
|
|
121
|
+
|
|
122
|
+
Config file: `C:\Users\elton\.honcho\config.json`
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"apiKey": "<bearer-token — never logged, never committed>",
|
|
127
|
+
"peerName": "elton",
|
|
128
|
+
"workspace": "claude_code",
|
|
129
|
+
"endpoint": {
|
|
130
|
+
"baseUrl": "https://honcho.pazzne.cloud"
|
|
131
|
+
},
|
|
132
|
+
"enabled": true,
|
|
133
|
+
"logging": false,
|
|
134
|
+
"inferenceEnabled": false,
|
|
135
|
+
"topN": 5,
|
|
136
|
+
"timeoutMs": 450
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Security**: `apiKey` is never printed to stdout, stderr, or any log. It is never committed to git.
|
|
141
|
+
|
|
142
|
+
### Session strategy
|
|
143
|
+
|
|
144
|
+
Session ID = `sha256(CWD)[:16]` — one bucket per project directory, never rotated.
|
|
145
|
+
All memories for a given directory accumulate in the same session indefinitely.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Setup
|
|
150
|
+
|
|
151
|
+
Run the interactive wizard:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bun run .claude/skills/honcho-memory/scripts/setup.js
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Or dry-run (no writes):
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
bun run .claude/skills/honcho-memory/scripts/setup.js --dry-run
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The wizard:
|
|
164
|
+
1. Verifies the Honcho connection.
|
|
165
|
+
2. Reads existing `memory/*.md` files (legacy memories).
|
|
166
|
+
3. Shows a preview/diff.
|
|
167
|
+
4. Asks for confirmation.
|
|
168
|
+
5. Backs up originals to `memory/backup-YYYYMMDD/`.
|
|
169
|
+
6. Migrates memories to Honcho.
|
|
170
|
+
7. Archives the original `.md` files.
|
|
171
|
+
|
|
172
|
+
Setup is **idempotent** — running it multiple times is safe.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Hooks registration
|
|
177
|
+
|
|
178
|
+
Hooks are registered in `C:\Users\elton\.claude\settings.json` (global scope):
|
|
179
|
+
|
|
180
|
+
- **UserPromptSubmit** → `bun run C:/development/tools/development-utility-kit/.claude/skills/honcho-memory/hooks/on-prompt-submit.js`
|
|
181
|
+
- **Stop** → `bun run C:/development/tools/development-utility-kit/.claude/skills/honcho-memory/hooks/on-stop.js`
|
|
182
|
+
|
|
183
|
+
Path uses forward slashes (IR-006 — accepted by the Claude Code hook runner on Windows).
|
|
184
|
+
Implementation lives in the harness at `C:/development/tools/development-utility-kit/.claude/skills/honcho-memory/` (Option B per D-003).
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Inference (deferred)
|
|
189
|
+
|
|
190
|
+
`inferenceEnabled: true` in config is a **stub** for `PLAN_honcho-inference.md`.
|
|
191
|
+
When enabled, `on-stop.js` emits `HONCHO_INFO: inference deferred to v2 PLAN, see PLAN_honcho-inference.md` in stderr and proceeds without LLM inference calls.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## API endpoints (verified — Honcho v3.0.6)
|
|
196
|
+
|
|
197
|
+
| Operation | Method | Path |
|
|
198
|
+
|---|---|---|
|
|
199
|
+
| Get/create session | POST/GET | `/v3/workspaces/{ws}/sessions` |
|
|
200
|
+
| Save memory (batch) | POST | `/v3/workspaces/{ws}/sessions/{session}/messages` |
|
|
201
|
+
| Soft-delete memory | PUT | `/v3/workspaces/{ws}/sessions/{session}/messages/{id}` |
|
|
202
|
+
| Peer-scoped search | POST | `/v3/workspaces/{ws}/peers/{peer}/search` |
|
|
203
|
+
| List session messages | POST | `/v3/workspaces/{ws}/sessions/{session}/messages/list` |
|
|
204
|
+
| Delete session (nuke) | DELETE | `/v3/workspaces/{ws}/sessions/{session}` |
|
|
205
|
+
| OpenAPI spec | GET | `/openapi.json` (root, not `/v3/openapi.json`) |
|
|
206
|
+
|
|
207
|
+
See `.claude/skills/honcho-memory/docs/api-endpoints-verified.md` for full details.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Honcho v3 API Endpoints — Verified
|
|
2
|
+
|
|
3
|
+
> verifiedAt: 2026-05-26T19:05:19Z
|
|
4
|
+
> Source: GET https://honcho.pazzne.cloud/openapi.json (note: spec served at root, not /v3/openapi.json)
|
|
5
|
+
> API version: 3.0.6 (openapi: 3.1.0)
|
|
6
|
+
|
|
7
|
+
## Summary of Deviations from DISCOVERY
|
|
8
|
+
|
|
9
|
+
The DISCOVERY document described a `workspaces/{ws}/apps/{app}/users/{user}/...` hierarchy.
|
|
10
|
+
The actual v3 API uses `workspaces/{ws}/sessions/{session}/...` with `peers/{peer}` instead of users/apps.
|
|
11
|
+
There is **no individual message DELETE** endpoint — `deleteMemory` is implemented by deleting the containing session.
|
|
12
|
+
|
|
13
|
+
## Verified Endpoints (6 operations mapped to client functions)
|
|
14
|
+
|
|
15
|
+
| Client Function | Method | Actual Path | operationId | DISCOVERY Path | Status |
|
|
16
|
+
|---|---|---|---|---|---|
|
|
17
|
+
| `getOrCreateApp` | `POST` | `/v3/workspaces` | `get_or_create_workspace_v3_workspaces_post` | `/v3/workspaces/{ws}/apps` | `differs: no apps concept — workspace IS the app` |
|
|
18
|
+
| `getOrCreateSession` | `POST` | `/v3/workspaces/{workspace_id}/sessions` | `get_or_create_session_v3_workspaces__workspace_id__sessions_post` | `/v3/workspaces/{ws}/apps/{app}/users/{user}/sessions` | `differs: no user/app nesting` |
|
|
19
|
+
| `saveMemory` | `POST` | `/v3/workspaces/{workspace_id}/sessions/{session_id}/messages` | `create_messages_for_session_v3_workspaces__workspace_id__sessions__session_id__messages_post` | `/v3/workspaces/{ws}/apps/{app}/users/{user}/sessions/{session}/messages` | `differs: shorter path, batch body` |
|
|
20
|
+
| `searchMemories` | `POST` | `/v3/workspaces/{workspace_id}/peers/{peer_id}/search` | `search_peer_v3_workspaces__workspace_id__peers__peer_id__search_post` | `/v3/workspaces/{ws}/apps/{app}/users/{user}/search` | `differs: peer-scoped, not user-scoped` |
|
|
21
|
+
| `listMemories` | `POST` | `/v3/workspaces/{workspace_id}/sessions/{session_id}/messages/list` | `get_messages_v3_workspaces__workspace_id__sessions__session_id__messages_list_post` | `/v3/workspaces/{ws}/apps/{app}/users/{user}/sessions/{session}/messages` | `differs: POST + /list suffix` |
|
|
22
|
+
| `deleteMemory` | `DELETE` | `/v3/workspaces/{workspace_id}/sessions/{session_id}` | `delete_session_v3_workspaces__workspace_id__sessions__session_id__delete` | `DELETE /v3/workspaces/{ws}/apps/{app}/users/{user}/sessions/{session}/messages/{id}` | `differs: no individual message delete; deletes whole session` |
|
|
23
|
+
|
|
24
|
+
## Additional Useful Endpoints
|
|
25
|
+
|
|
26
|
+
| Method | Path | Summary |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `GET` | `/health` | Health check (no auth required) |
|
|
29
|
+
| `POST` | `/v3/workspaces/{workspace_id}/search` | Search across entire workspace |
|
|
30
|
+
| `POST` | `/v3/workspaces/{workspace_id}/sessions/{session_id}/search` | Search within session |
|
|
31
|
+
| `DELETE` | `/v3/workspaces/{workspace_id}` | Delete workspace |
|
|
32
|
+
| `PUT` | `/v3/workspaces/{workspace_id}/sessions/{session_id}/messages/{message_id}` | Update message metadata |
|
|
33
|
+
|
|
34
|
+
## Key Schema Differences
|
|
35
|
+
|
|
36
|
+
### WorkspaceCreate (POST /v3/workspaces)
|
|
37
|
+
```json
|
|
38
|
+
{ "id": "string (required, pattern: ^[a-zA-Z0-9_-]+$)", "metadata": "object" }
|
|
39
|
+
```
|
|
40
|
+
Response: workspace object with same `id`.
|
|
41
|
+
|
|
42
|
+
### SessionCreate (POST /v3/workspaces/{workspace_id}/sessions)
|
|
43
|
+
```json
|
|
44
|
+
{ "id": "string (required)", "metadata": "object|null", "peers": "object|null" }
|
|
45
|
+
```
|
|
46
|
+
Response: session object.
|
|
47
|
+
|
|
48
|
+
### MessageBatchCreate (POST .../messages)
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"messages": [
|
|
52
|
+
{ "content": "string (required)", "peer_id": "string (required)", "metadata": "object|null" }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
**Note**: `peer_id` is required per message. Use `peerName` from config as the peer_id.
|
|
57
|
+
|
|
58
|
+
### MessageSearchOptions (POST .../peers/{peer_id}/search)
|
|
59
|
+
```json
|
|
60
|
+
{ "query": "string (required)", "filters": "object|null", "limit": "integer (1-100, default 10)" }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### MessageGet (POST .../messages/list)
|
|
64
|
+
```json
|
|
65
|
+
{ "filters": "object|null" }
|
|
66
|
+
```
|
|
67
|
+
Response: `Page[Message]` with `{ items, total, page, size, pages }`.
|
|
68
|
+
|
|
69
|
+
## Architecture Notes for honcho-client.js
|
|
70
|
+
|
|
71
|
+
- **Workspace** = equivalent to "app" in DISCOVERY. Use fixed id from config (`hosts.claude_code.workspace`).
|
|
72
|
+
- **Session** = per-directory session. ID derived from SHA-256(CWD)[:16].
|
|
73
|
+
- **Peer** = the user identity. Use `peerName` from config (default: "elton").
|
|
74
|
+
- **getOrCreateApp** in client = `POST /v3/workspaces` (idempotent by id).
|
|
75
|
+
- **deleteMemory** in client = `DELETE /v3/workspaces/{ws}/sessions/{sessionId}` (entire session, not single message). For granular "forget", use `PUT .../messages/{id}` to update metadata with `deleted: true` marker.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* on-prompt-submit.js — UserPromptSubmit hook
|
|
3
|
+
*
|
|
4
|
+
* Triggered by Claude Code before each user prompt is submitted.
|
|
5
|
+
* Reads the user's prompt from stdin, then:
|
|
6
|
+
* 1. Detects explicit memory triggers ("lembra que", "remember that", "memoriza", "never ", "always ")
|
|
7
|
+
* → saves memory immediately with metadata.type = "explicit", metadata.source = "user"
|
|
8
|
+
* 2. Runs hybrid search in Promise.all (peer-scoped + session-scoped) within timeout budget
|
|
9
|
+
* 3. Injects [HONCHO MEMORY] block into stdout as system prompt extension
|
|
10
|
+
*
|
|
11
|
+
* Telemetry: stdout JSON contains peerSearchExecuted + sessionListExecuted fields.
|
|
12
|
+
*
|
|
13
|
+
* Env vars:
|
|
14
|
+
* HONCHO_DRY_RUN=1 — skip real Honcho calls, emit telemetry JSON to stdout
|
|
15
|
+
* HONCHO_BASE_URL — override base URL (env takes precedence over config)
|
|
16
|
+
* HONCHO_TIMEOUT_MS — override timeout in ms
|
|
17
|
+
*
|
|
18
|
+
* Exit codes:
|
|
19
|
+
* 0 — always (NFR-002: never blocks Claude Code)
|
|
20
|
+
*
|
|
21
|
+
* References: FR-003a, FR-003b, FR-003c, BR-001, BR-008, NFR-001, NFR-002
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { createHash } from "crypto";
|
|
25
|
+
import { createClient, loadConfig } from "../lib/honcho-client.js";
|
|
26
|
+
import { buildContextBlock } from "../lib/memory-injector.js";
|
|
27
|
+
|
|
28
|
+
const DRY_RUN = process.env.HONCHO_DRY_RUN === "1";
|
|
29
|
+
|
|
30
|
+
const CONFIG_PATH = "C:\\Users\\elton\\.honcho\\config.json";
|
|
31
|
+
|
|
32
|
+
/** Read config, override with env vars where applicable. Returns null if disabled or missing. */
|
|
33
|
+
function getEffectiveConfig() {
|
|
34
|
+
const cfg = loadConfig();
|
|
35
|
+
|
|
36
|
+
// If env vars specify base URL, build a synthetic config
|
|
37
|
+
if (process.env.HONCHO_BASE_URL) {
|
|
38
|
+
// Build minimal config from env — useful for testing with no config file
|
|
39
|
+
const base = {
|
|
40
|
+
apiKey: cfg?.apiKey ?? "dry-run-key",
|
|
41
|
+
peerName: cfg?.peerName ?? "elton",
|
|
42
|
+
workspace: cfg?.workspace ?? "claude_code",
|
|
43
|
+
endpoint: { baseUrl: process.env.HONCHO_BASE_URL },
|
|
44
|
+
enabled: true,
|
|
45
|
+
topN: cfg?.topN ?? 5,
|
|
46
|
+
timeoutMs: process.env.HONCHO_TIMEOUT_MS
|
|
47
|
+
? parseInt(process.env.HONCHO_TIMEOUT_MS, 10)
|
|
48
|
+
: (cfg?.timeoutMs ?? 450),
|
|
49
|
+
};
|
|
50
|
+
return base;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!cfg) return null;
|
|
54
|
+
if (cfg.enabled === false) return null;
|
|
55
|
+
|
|
56
|
+
// Apply env override for timeout
|
|
57
|
+
if (process.env.HONCHO_TIMEOUT_MS) {
|
|
58
|
+
cfg.timeoutMs = parseInt(process.env.HONCHO_TIMEOUT_MS, 10);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return cfg;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Derive session ID from CWD: sha256(CWD)[:16] */
|
|
65
|
+
function deriveSessionId(cwd) {
|
|
66
|
+
return createHash("sha256").update(cwd).digest("hex").slice(0, 16);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Detect explicit memory trigger patterns (BR-001) */
|
|
70
|
+
function detectExplicitTrigger(prompt) {
|
|
71
|
+
const lower = prompt.toLowerCase();
|
|
72
|
+
return (
|
|
73
|
+
lower.includes("lembra que") ||
|
|
74
|
+
lower.includes("remember that") ||
|
|
75
|
+
lower.includes("memoriza") ||
|
|
76
|
+
lower.startsWith("never ") ||
|
|
77
|
+
lower.includes("\nnever ") ||
|
|
78
|
+
lower.startsWith("always ") ||
|
|
79
|
+
lower.includes("\nalways ")
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Write to stderr without logging apiKey */
|
|
84
|
+
function warn(msg) {
|
|
85
|
+
process.stderr.write("HONCHO_WARN: " + msg + "\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function main() {
|
|
89
|
+
// Read stdin (prompt text)
|
|
90
|
+
let prompt = "";
|
|
91
|
+
try {
|
|
92
|
+
const chunks = [];
|
|
93
|
+
for await (const chunk of process.stdin) {
|
|
94
|
+
chunks.push(chunk);
|
|
95
|
+
}
|
|
96
|
+
prompt = Buffer.concat(chunks).toString("utf8").trim();
|
|
97
|
+
} catch {
|
|
98
|
+
// stdin read failed — proceed with empty prompt
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const cfg = getEffectiveConfig();
|
|
102
|
+
const cwd = process.cwd();
|
|
103
|
+
const sessionId = deriveSessionId(cwd);
|
|
104
|
+
const isExplicit = detectExplicitTrigger(prompt);
|
|
105
|
+
|
|
106
|
+
// DRY_RUN mode: simulate execution without real Honcho calls
|
|
107
|
+
if (DRY_RUN) {
|
|
108
|
+
const telemetry = {
|
|
109
|
+
dryRun: true,
|
|
110
|
+
peerSearchExecuted: true,
|
|
111
|
+
sessionListExecuted: true,
|
|
112
|
+
saved: isExplicit ? true : false,
|
|
113
|
+
sessionId,
|
|
114
|
+
prompt: prompt.slice(0, 100),
|
|
115
|
+
};
|
|
116
|
+
if (isExplicit) {
|
|
117
|
+
telemetry.savedType = "explicit";
|
|
118
|
+
telemetry.savedSource = "user";
|
|
119
|
+
}
|
|
120
|
+
process.stdout.write(JSON.stringify(telemetry) + "\n");
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// No config or disabled — silent no-op
|
|
125
|
+
if (!cfg) {
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const workspace = cfg.workspace ?? "claude_code";
|
|
130
|
+
const peerId = cfg.peerName ?? "elton";
|
|
131
|
+
const topN = cfg.topN ?? 5;
|
|
132
|
+
const timeoutMs = cfg.timeoutMs ?? 450;
|
|
133
|
+
const project = cwd.split(/[/\\]/).pop() ?? "unknown";
|
|
134
|
+
|
|
135
|
+
const client = createClient({
|
|
136
|
+
baseUrl: cfg.endpoint.baseUrl,
|
|
137
|
+
apiKey: cfg.apiKey,
|
|
138
|
+
timeoutMs,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Step 1: Save explicit memory immediately (BR-001)
|
|
142
|
+
if (isExplicit) {
|
|
143
|
+
try {
|
|
144
|
+
await client.saveMemory(workspace, sessionId, peerId, prompt, {
|
|
145
|
+
type: "explicit",
|
|
146
|
+
source: "user",
|
|
147
|
+
project,
|
|
148
|
+
directory: cwd,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
});
|
|
151
|
+
} catch {
|
|
152
|
+
// Never block — ignore save errors
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Step 2: Hybrid search within timeout budget (FR-003a + FR-003b, NFR-001)
|
|
157
|
+
let peerResults = null;
|
|
158
|
+
let sessionResults = null;
|
|
159
|
+
let peerSearchExecuted = false;
|
|
160
|
+
let sessionListExecuted = false;
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
const [peerRes, sessionRes] = await Promise.all([
|
|
164
|
+
client.searchMemories(workspace, peerId, prompt || "general context", topN).then((r) => {
|
|
165
|
+
peerSearchExecuted = true;
|
|
166
|
+
return r;
|
|
167
|
+
}),
|
|
168
|
+
client.listMemories(workspace, sessionId, {}).then((r) => {
|
|
169
|
+
sessionListExecuted = true;
|
|
170
|
+
return r;
|
|
171
|
+
}),
|
|
172
|
+
]);
|
|
173
|
+
peerResults = peerRes;
|
|
174
|
+
sessionResults = sessionRes;
|
|
175
|
+
} catch {
|
|
176
|
+
// Failure in Promise.all — warn and continue
|
|
177
|
+
warn("search failed, proceeding without memories");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// If both failed (null), emit warning
|
|
181
|
+
if (!peerResults && !sessionResults) {
|
|
182
|
+
warn("no memories retrieved — Honcho may be unreachable");
|
|
183
|
+
process.exit(0);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Step 3: Merge results (FR-003c)
|
|
187
|
+
// peer-search returns scored items; session-list returns recency-ordered items
|
|
188
|
+
const peerItems = peerResults?.items ?? [];
|
|
189
|
+
const sessionItems = sessionResults?.items ?? [];
|
|
190
|
+
|
|
191
|
+
// Merge: peer items first (relevance-scored), then session items (recency proxy)
|
|
192
|
+
// Deduplicate by content (simple string match)
|
|
193
|
+
const seen = new Set();
|
|
194
|
+
const merged = [];
|
|
195
|
+
for (const item of [...peerItems, ...sessionItems]) {
|
|
196
|
+
const key = item.content?.trim();
|
|
197
|
+
if (key && !seen.has(key)) {
|
|
198
|
+
seen.add(key);
|
|
199
|
+
merged.push(item);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const topMemories = merged.slice(0, topN);
|
|
204
|
+
|
|
205
|
+
if (topMemories.length === 0) {
|
|
206
|
+
process.exit(0);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Step 4: Build and inject context block
|
|
210
|
+
const contextBlock = buildContextBlock(topMemories);
|
|
211
|
+
if (contextBlock) {
|
|
212
|
+
process.stdout.write(contextBlock + "\n");
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
process.exit(0);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
main().catch((err) => {
|
|
219
|
+
warn("unexpected error: " + (err?.message ?? String(err)));
|
|
220
|
+
process.exit(0);
|
|
221
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* on-stop.js — Stop hook
|
|
3
|
+
*
|
|
4
|
+
* Triggered by Claude Code when a session ends.
|
|
5
|
+
* Extracts the active feature/sprint from CLAUDE.md and recent git log,
|
|
6
|
+
* then saves a memory with metadata.type = "project-context".
|
|
7
|
+
*
|
|
8
|
+
* If inferenceEnabled is true (config or HONCHO_INFERENCE_ENABLED=true env):
|
|
9
|
+
* writes "HONCHO_INFO: inference deferred to v2 PLAN, see PLAN_honcho-inference.md" to stderr
|
|
10
|
+
* and proceeds WITHOUT performing inference (NFR-007, BR-006).
|
|
11
|
+
*
|
|
12
|
+
* Env vars:
|
|
13
|
+
* HONCHO_DRY_RUN=1 — skip real Honcho calls, print JSON to stdout
|
|
14
|
+
* HONCHO_BASE_URL — override base URL
|
|
15
|
+
* HONCHO_TIMEOUT_MS — override timeout in ms
|
|
16
|
+
* HONCHO_INFERENCE_ENABLED — "true" to enable inference stub (writes HONCHO_INFO)
|
|
17
|
+
*
|
|
18
|
+
* Exit codes:
|
|
19
|
+
* 0 — always (IR-004: non-blocking, fail-silent)
|
|
20
|
+
*
|
|
21
|
+
* References: FR-004, BR-006, NFR-007, IR-004
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { existsSync, readFileSync } from "fs";
|
|
25
|
+
import { join } from "path";
|
|
26
|
+
import { execSync } from "child_process";
|
|
27
|
+
import { createHash } from "crypto";
|
|
28
|
+
import { createClient, loadConfig } from "../lib/honcho-client.js";
|
|
29
|
+
|
|
30
|
+
const DRY_RUN = process.env.HONCHO_DRY_RUN === "1";
|
|
31
|
+
const INFERENCE_ENABLED =
|
|
32
|
+
process.env.HONCHO_INFERENCE_ENABLED === "true";
|
|
33
|
+
|
|
34
|
+
/** Write to stderr */
|
|
35
|
+
function warn(msg) {
|
|
36
|
+
process.stderr.write("HONCHO_WARN: " + msg + "\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function info(msg) {
|
|
40
|
+
process.stderr.write("HONCHO_INFO: " + msg + "\n");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Derive session ID from CWD: sha256(CWD)[:16] */
|
|
44
|
+
function deriveSessionId(cwd) {
|
|
45
|
+
return createHash("sha256").update(cwd).digest("hex").slice(0, 16);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extract active feature/sprint from CLAUDE.md in the given directory.
|
|
50
|
+
* Returns a short string or null.
|
|
51
|
+
*/
|
|
52
|
+
function extractFeatureFromClaudeMd(cwd) {
|
|
53
|
+
const claudeMdPath = join(cwd, "CLAUDE.md");
|
|
54
|
+
if (!existsSync(claudeMdPath)) return null;
|
|
55
|
+
try {
|
|
56
|
+
const content = readFileSync(claudeMdPath, "utf8");
|
|
57
|
+
// Look for sprint / feature / plan mentions
|
|
58
|
+
const sprintMatch = content.match(/(?:sprint|Sprint)\s+([\w-]+)/i);
|
|
59
|
+
const planMatch = content.match(/PLAN_(\w[\w-]*)/i);
|
|
60
|
+
const featureMatch = content.match(/feature\/([\w-]+)/i);
|
|
61
|
+
if (planMatch) return `PLAN_${planMatch[1]}`;
|
|
62
|
+
if (sprintMatch) return `Sprint ${sprintMatch[1]}`;
|
|
63
|
+
if (featureMatch) return `feature/${featureMatch[1]}`;
|
|
64
|
+
return null;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Extract recent git log summary (last 3 commits, one-line format).
|
|
72
|
+
* Returns a string or null.
|
|
73
|
+
*/
|
|
74
|
+
function extractRecentGitLog(cwd) {
|
|
75
|
+
try {
|
|
76
|
+
const log = execSync("git log --oneline -3", {
|
|
77
|
+
cwd,
|
|
78
|
+
timeout: 2000,
|
|
79
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
80
|
+
encoding: "utf8",
|
|
81
|
+
});
|
|
82
|
+
return log.trim();
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Get effective config, applying env overrides. */
|
|
89
|
+
function getEffectiveConfig() {
|
|
90
|
+
const cfg = loadConfig();
|
|
91
|
+
|
|
92
|
+
if (process.env.HONCHO_BASE_URL) {
|
|
93
|
+
return {
|
|
94
|
+
apiKey: cfg?.apiKey ?? "dry-run-key",
|
|
95
|
+
peerName: cfg?.peerName ?? "elton",
|
|
96
|
+
workspace: cfg?.workspace ?? "claude_code",
|
|
97
|
+
endpoint: { baseUrl: process.env.HONCHO_BASE_URL },
|
|
98
|
+
enabled: true,
|
|
99
|
+
timeoutMs: process.env.HONCHO_TIMEOUT_MS
|
|
100
|
+
? parseInt(process.env.HONCHO_TIMEOUT_MS, 10)
|
|
101
|
+
: (cfg?.timeoutMs ?? 450),
|
|
102
|
+
inferenceEnabled: INFERENCE_ENABLED || (cfg?.inferenceEnabled ?? false),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!cfg) return null;
|
|
107
|
+
|
|
108
|
+
if (process.env.HONCHO_TIMEOUT_MS) {
|
|
109
|
+
cfg.timeoutMs = parseInt(process.env.HONCHO_TIMEOUT_MS, 10);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// env var overrides config flag
|
|
113
|
+
cfg.inferenceEnabled = INFERENCE_ENABLED || (cfg.inferenceEnabled ?? false);
|
|
114
|
+
|
|
115
|
+
return cfg;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function main() {
|
|
119
|
+
const cwd = process.cwd();
|
|
120
|
+
const sessionId = deriveSessionId(cwd);
|
|
121
|
+
const project = cwd.split(/[/\\]/).pop() ?? "unknown";
|
|
122
|
+
|
|
123
|
+
// Extract context from CLAUDE.md and git log
|
|
124
|
+
const featureInfo = extractFeatureFromClaudeMd(cwd);
|
|
125
|
+
const gitLog = extractRecentGitLog(cwd);
|
|
126
|
+
|
|
127
|
+
const contextParts = [];
|
|
128
|
+
if (featureInfo) contextParts.push(`Active: ${featureInfo}`);
|
|
129
|
+
if (gitLog) contextParts.push(`Recent commits:\n${gitLog}`);
|
|
130
|
+
contextParts.push(`Directory: ${cwd}`);
|
|
131
|
+
contextParts.push(`Project: ${project}`);
|
|
132
|
+
|
|
133
|
+
const content = contextParts.join("\n");
|
|
134
|
+
|
|
135
|
+
const memoryPayload = {
|
|
136
|
+
type: "project-context",
|
|
137
|
+
project,
|
|
138
|
+
directory: cwd,
|
|
139
|
+
timestamp: new Date().toISOString(),
|
|
140
|
+
source: "user",
|
|
141
|
+
sessionId,
|
|
142
|
+
featureInfo: featureInfo ?? null,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Check inference flag (BR-006, NFR-007) — always before any Honcho call
|
|
146
|
+
const cfg = getEffectiveConfig();
|
|
147
|
+
const inferenceEnabled = cfg?.inferenceEnabled || INFERENCE_ENABLED;
|
|
148
|
+
|
|
149
|
+
if (inferenceEnabled) {
|
|
150
|
+
info("inference deferred to v2 PLAN, see PLAN_honcho-inference.md");
|
|
151
|
+
// No LLM call — proceed with project-context save only
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// DRY_RUN mode
|
|
155
|
+
if (DRY_RUN) {
|
|
156
|
+
const output = {
|
|
157
|
+
dryRun: true,
|
|
158
|
+
...memoryPayload,
|
|
159
|
+
};
|
|
160
|
+
process.stdout.write(JSON.stringify(output) + "\n");
|
|
161
|
+
process.exit(0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// No config or disabled — silent no-op
|
|
165
|
+
if (!cfg || cfg.enabled === false) {
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const workspace = cfg.workspace ?? "claude_code";
|
|
170
|
+
const peerId = cfg.peerName ?? "elton";
|
|
171
|
+
const timeoutMs = Math.min(cfg.timeoutMs ?? 450, 2000); // cap at 2s for stop hook
|
|
172
|
+
|
|
173
|
+
const client = createClient({
|
|
174
|
+
baseUrl: cfg.endpoint.baseUrl,
|
|
175
|
+
apiKey: cfg.apiKey,
|
|
176
|
+
timeoutMs,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Save project-context memory
|
|
180
|
+
try {
|
|
181
|
+
await client.saveMemory(workspace, sessionId, peerId, content, memoryPayload);
|
|
182
|
+
} catch {
|
|
183
|
+
// Non-blocking — ignore errors
|
|
184
|
+
warn("failed to save project-context memory");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main().catch((err) => {
|
|
191
|
+
warn("unexpected error in on-stop: " + (err?.message ?? String(err)));
|
|
192
|
+
process.exit(0);
|
|
193
|
+
});
|