memorix 1.9.9 → 1.9.10
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/CHANGELOG.md +9 -0
- package/dist/cli/index.js +91 -23
- package/dist/index.js +91 -23
- package/dist/memcode-runtime/CHANGELOG.md +9 -0
- package/dist/sdk.js +90 -22
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/INTEGRATIONS.md +1 -1
- package/docs/README.md +1 -1
- package/docs/SETUP.md +1 -1
- package/package.json +1 -1
- package/plugins/antigravity/memorix/plugin.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/hermes/memorix/plugin.yaml +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/hooks/installers/index.ts +89 -21
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ All notable changes to this project will be documented in this file.
|
|
|
6
6
|
|
|
7
7
|
No unreleased changes.
|
|
8
8
|
|
|
9
|
+
## [1.9.10] - 2026-10-08
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **OpenCode 1.x regression** -- generated plugins now include the v1
|
|
13
|
+
`server` field alongside the v2 `setup` contract, so OpenCode 1.x can load
|
|
14
|
+
the legacy named export. Lifecycle, file, command, message, and compaction
|
|
15
|
+
events are also forwarded through the v1 generic `event` hook, with a longer
|
|
16
|
+
Windows hook timeout to reduce stale Bun timer failures.
|
|
17
|
+
|
|
9
18
|
## [1.9.9] - 2026-10-02
|
|
10
19
|
|
|
11
20
|
### Added
|
package/dist/cli/index.js
CHANGED
|
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
|
|
|
3232
3232
|
|
|
3233
3233
|
// src/cli/version.ts
|
|
3234
3234
|
function getCliVersion() {
|
|
3235
|
-
return true ? "1.9.
|
|
3235
|
+
return true ? "1.9.10" : pkg.version;
|
|
3236
3236
|
}
|
|
3237
3237
|
var init_version = __esm({
|
|
3238
3238
|
"src/cli/version.ts"() {
|
|
@@ -195509,6 +195509,8 @@ function generateOpenCodePlugin() {
|
|
|
195509
195509
|
*/
|
|
195510
195510
|
import { spawnSync } from 'node:child_process';
|
|
195511
195511
|
|
|
195512
|
+
const HOOK_TIMEOUT_MS = 30_000;
|
|
195513
|
+
|
|
195512
195514
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
195513
195515
|
// Generate a stable session ID for this plugin lifetime
|
|
195514
195516
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
@@ -195534,14 +195536,14 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
195534
195536
|
* - spawnSync is simpler: no stream lifecycle, no writer.close() bugs
|
|
195535
195537
|
* - stdin pipe via input option is reliable cross-platform
|
|
195536
195538
|
*/
|
|
195537
|
-
function runHook(payload) {
|
|
195538
|
-
payload.session_id =
|
|
195539
|
+
function runHook(payload, activeSessionId = sessionId) {
|
|
195540
|
+
payload.session_id = activeSessionId;
|
|
195539
195541
|
const data = JSON.stringify(payload);
|
|
195540
195542
|
const eventName = payload.hook_event_name || 'unknown';
|
|
195541
195543
|
try {
|
|
195542
195544
|
const result = spawnSync(hookCommand, ['hook'], {
|
|
195543
195545
|
input: data,
|
|
195544
|
-
timeout:
|
|
195546
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
195545
195547
|
encoding: 'utf-8',
|
|
195546
195548
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
195547
195549
|
shell: process.platform === 'win32',
|
|
@@ -195586,7 +195588,87 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
195586
195588
|
.trim();
|
|
195587
195589
|
}
|
|
195588
195590
|
|
|
195591
|
+
function flushAssistantResponse(activeSessionId = sessionId) {
|
|
195592
|
+
if (!pendingAssistantResponse?.text) return;
|
|
195593
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
195594
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
195595
|
+
: pendingAssistantResponse.text;
|
|
195596
|
+
if (deliveryKey === lastDeliveredAssistantKey) return;
|
|
195597
|
+
runHook({
|
|
195598
|
+
agent: 'opencode',
|
|
195599
|
+
hook_event_name: 'message.updated',
|
|
195600
|
+
ai_response: pendingAssistantResponse.text,
|
|
195601
|
+
message_id: pendingAssistantResponse.id,
|
|
195602
|
+
cwd: directory,
|
|
195603
|
+
}, activeSessionId);
|
|
195604
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
195605
|
+
}
|
|
195606
|
+
|
|
195607
|
+
function eventSessionId(event) {
|
|
195608
|
+
const properties = event?.properties ?? {};
|
|
195609
|
+
const value = properties.sessionID ?? properties.sessionId ?? properties.info?.id;
|
|
195610
|
+
return typeof value === 'string' && value ? value : sessionId;
|
|
195611
|
+
}
|
|
195612
|
+
|
|
195613
|
+
async function handleEvent({ event }) {
|
|
195614
|
+
const properties = event?.properties ?? {};
|
|
195615
|
+
const activeSessionId = eventSessionId(event);
|
|
195616
|
+
switch (event?.type) {
|
|
195617
|
+
case 'session.created':
|
|
195618
|
+
runHook({
|
|
195619
|
+
agent: 'opencode',
|
|
195620
|
+
hook_event_name: 'session.created',
|
|
195621
|
+
cwd: directory,
|
|
195622
|
+
}, activeSessionId);
|
|
195623
|
+
break;
|
|
195624
|
+
case 'session.idle':
|
|
195625
|
+
flushAssistantResponse(activeSessionId);
|
|
195626
|
+
runHook({
|
|
195627
|
+
agent: 'opencode',
|
|
195628
|
+
hook_event_name: 'session.idle',
|
|
195629
|
+
cwd: directory,
|
|
195630
|
+
}, activeSessionId);
|
|
195631
|
+
break;
|
|
195632
|
+
case 'file.edited':
|
|
195633
|
+
runHook({
|
|
195634
|
+
agent: 'opencode',
|
|
195635
|
+
hook_event_name: 'file.edited',
|
|
195636
|
+
file_path: properties.file ?? properties.path ?? '',
|
|
195637
|
+
cwd: directory,
|
|
195638
|
+
}, activeSessionId);
|
|
195639
|
+
break;
|
|
195640
|
+
case 'command.executed':
|
|
195641
|
+
runHook({
|
|
195642
|
+
agent: 'opencode',
|
|
195643
|
+
hook_event_name: 'command.executed',
|
|
195644
|
+
command: properties.name ?? properties.command ?? '',
|
|
195645
|
+
cwd: directory,
|
|
195646
|
+
}, activeSessionId);
|
|
195647
|
+
break;
|
|
195648
|
+
case 'message.updated': {
|
|
195649
|
+
const message = properties.info ?? properties.message ?? properties;
|
|
195650
|
+
if (message?.role !== 'assistant') break;
|
|
195651
|
+
const text = extractMessageText(message);
|
|
195652
|
+
if (!text) break;
|
|
195653
|
+
pendingAssistantResponse = { id: message.id, text };
|
|
195654
|
+
break;
|
|
195655
|
+
}
|
|
195656
|
+
case 'session.compacted':
|
|
195657
|
+
runHook({
|
|
195658
|
+
agent: 'opencode',
|
|
195659
|
+
hook_event_name: 'session.compacted',
|
|
195660
|
+
cwd: directory,
|
|
195661
|
+
}, activeSessionId);
|
|
195662
|
+
break;
|
|
195663
|
+
default:
|
|
195664
|
+
break;
|
|
195665
|
+
}
|
|
195666
|
+
}
|
|
195667
|
+
|
|
195589
195668
|
return {
|
|
195669
|
+
// OpenCode 1.x delivers lifecycle/file/command/message events through this
|
|
195670
|
+
// generic hook. The named keys below remain for older compatible hosts.
|
|
195671
|
+
event: handleEvent,
|
|
195590
195672
|
/** Session created \u2014 record session start */
|
|
195591
195673
|
'session.created': async ({ session }) => {
|
|
195592
195674
|
runHook({
|
|
@@ -195598,21 +195680,7 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
195598
195680
|
|
|
195599
195681
|
/** Session idle \u2014 record session end */
|
|
195600
195682
|
'session.idle': async ({ session }) => {
|
|
195601
|
-
|
|
195602
|
-
const deliveryKey = pendingAssistantResponse.id
|
|
195603
|
-
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
195604
|
-
: pendingAssistantResponse.text;
|
|
195605
|
-
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
195606
|
-
runHook({
|
|
195607
|
-
agent: 'opencode',
|
|
195608
|
-
hook_event_name: 'message.updated',
|
|
195609
|
-
ai_response: pendingAssistantResponse.text,
|
|
195610
|
-
message_id: pendingAssistantResponse.id,
|
|
195611
|
-
cwd: directory,
|
|
195612
|
-
});
|
|
195613
|
-
lastDeliveredAssistantKey = deliveryKey;
|
|
195614
|
-
}
|
|
195615
|
-
}
|
|
195683
|
+
flushAssistantResponse();
|
|
195616
195684
|
runHook({
|
|
195617
195685
|
agent: 'opencode',
|
|
195618
195686
|
hook_event_name: 'session.idle',
|
|
@@ -195720,7 +195788,7 @@ function v2RunHook(payload, directory, sessionId) {
|
|
|
195720
195788
|
try {
|
|
195721
195789
|
const result = spawnSync(v2HookCommand, ['hook'], {
|
|
195722
195790
|
input: JSON.stringify(nextPayload),
|
|
195723
|
-
timeout:
|
|
195791
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
195724
195792
|
encoding: 'utf-8',
|
|
195725
195793
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
195726
195794
|
shell: process.platform === 'win32',
|
|
@@ -195844,7 +195912,7 @@ function setup(ctx) {
|
|
|
195844
195912
|
return () => controller.abort();
|
|
195845
195913
|
}
|
|
195846
195914
|
|
|
195847
|
-
export default { id: 'memorix', setup };
|
|
195915
|
+
export default { id: 'memorix', server: MemorixPlugin, setup };
|
|
195848
195916
|
`;
|
|
195849
195917
|
}
|
|
195850
195918
|
async function installOpenCodeSkills(projectRoot, global2 = false) {
|
|
@@ -196670,7 +196738,7 @@ var init_installers = __esm({
|
|
|
196670
196738
|
"use strict";
|
|
196671
196739
|
init_esm_shims();
|
|
196672
196740
|
init_official_skills();
|
|
196673
|
-
OPENCODE_PLUGIN_VERSION =
|
|
196741
|
+
OPENCODE_PLUGIN_VERSION = 9;
|
|
196674
196742
|
AGENT_SKILL_DIRS = {
|
|
196675
196743
|
cursor: { project: path31.join(".cursor", "skills"), global: path31.join(".cursor", "skills") },
|
|
196676
196744
|
windsurf: { project: path31.join(".windsurf", "skills"), global: path31.join(".windsurf", "skills") },
|
|
@@ -209197,7 +209265,7 @@ var init_tool_profile = __esm({
|
|
|
209197
209265
|
function getMcpServerInfo() {
|
|
209198
209266
|
return {
|
|
209199
209267
|
name: "memorix",
|
|
209200
|
-
version: true ? "1.9.
|
|
209268
|
+
version: true ? "1.9.10" : "1.0.1"
|
|
209201
209269
|
};
|
|
209202
209270
|
}
|
|
209203
209271
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
package/dist/index.js
CHANGED
|
@@ -160121,7 +160121,7 @@ var init_request_context = __esm({
|
|
|
160121
160121
|
function getMcpServerInfo() {
|
|
160122
160122
|
return {
|
|
160123
160123
|
name: "memorix",
|
|
160124
|
-
version: true ? "1.9.
|
|
160124
|
+
version: true ? "1.9.10" : "1.0.1"
|
|
160125
160125
|
};
|
|
160126
160126
|
}
|
|
160127
160127
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
|
@@ -169930,6 +169930,8 @@ function generateOpenCodePlugin() {
|
|
|
169930
169930
|
*/
|
|
169931
169931
|
import { spawnSync } from 'node:child_process';
|
|
169932
169932
|
|
|
169933
|
+
const HOOK_TIMEOUT_MS = 30_000;
|
|
169934
|
+
|
|
169933
169935
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
169934
169936
|
// Generate a stable session ID for this plugin lifetime
|
|
169935
169937
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
@@ -169955,14 +169957,14 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
169955
169957
|
* - spawnSync is simpler: no stream lifecycle, no writer.close() bugs
|
|
169956
169958
|
* - stdin pipe via input option is reliable cross-platform
|
|
169957
169959
|
*/
|
|
169958
|
-
function runHook(payload) {
|
|
169959
|
-
payload.session_id =
|
|
169960
|
+
function runHook(payload, activeSessionId = sessionId) {
|
|
169961
|
+
payload.session_id = activeSessionId;
|
|
169960
169962
|
const data = JSON.stringify(payload);
|
|
169961
169963
|
const eventName = payload.hook_event_name || 'unknown';
|
|
169962
169964
|
try {
|
|
169963
169965
|
const result = spawnSync(hookCommand, ['hook'], {
|
|
169964
169966
|
input: data,
|
|
169965
|
-
timeout:
|
|
169967
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
169966
169968
|
encoding: 'utf-8',
|
|
169967
169969
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
169968
169970
|
shell: process.platform === 'win32',
|
|
@@ -170007,7 +170009,87 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
170007
170009
|
.trim();
|
|
170008
170010
|
}
|
|
170009
170011
|
|
|
170012
|
+
function flushAssistantResponse(activeSessionId = sessionId) {
|
|
170013
|
+
if (!pendingAssistantResponse?.text) return;
|
|
170014
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
170015
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
170016
|
+
: pendingAssistantResponse.text;
|
|
170017
|
+
if (deliveryKey === lastDeliveredAssistantKey) return;
|
|
170018
|
+
runHook({
|
|
170019
|
+
agent: 'opencode',
|
|
170020
|
+
hook_event_name: 'message.updated',
|
|
170021
|
+
ai_response: pendingAssistantResponse.text,
|
|
170022
|
+
message_id: pendingAssistantResponse.id,
|
|
170023
|
+
cwd: directory,
|
|
170024
|
+
}, activeSessionId);
|
|
170025
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
170026
|
+
}
|
|
170027
|
+
|
|
170028
|
+
function eventSessionId(event) {
|
|
170029
|
+
const properties = event?.properties ?? {};
|
|
170030
|
+
const value = properties.sessionID ?? properties.sessionId ?? properties.info?.id;
|
|
170031
|
+
return typeof value === 'string' && value ? value : sessionId;
|
|
170032
|
+
}
|
|
170033
|
+
|
|
170034
|
+
async function handleEvent({ event }) {
|
|
170035
|
+
const properties = event?.properties ?? {};
|
|
170036
|
+
const activeSessionId = eventSessionId(event);
|
|
170037
|
+
switch (event?.type) {
|
|
170038
|
+
case 'session.created':
|
|
170039
|
+
runHook({
|
|
170040
|
+
agent: 'opencode',
|
|
170041
|
+
hook_event_name: 'session.created',
|
|
170042
|
+
cwd: directory,
|
|
170043
|
+
}, activeSessionId);
|
|
170044
|
+
break;
|
|
170045
|
+
case 'session.idle':
|
|
170046
|
+
flushAssistantResponse(activeSessionId);
|
|
170047
|
+
runHook({
|
|
170048
|
+
agent: 'opencode',
|
|
170049
|
+
hook_event_name: 'session.idle',
|
|
170050
|
+
cwd: directory,
|
|
170051
|
+
}, activeSessionId);
|
|
170052
|
+
break;
|
|
170053
|
+
case 'file.edited':
|
|
170054
|
+
runHook({
|
|
170055
|
+
agent: 'opencode',
|
|
170056
|
+
hook_event_name: 'file.edited',
|
|
170057
|
+
file_path: properties.file ?? properties.path ?? '',
|
|
170058
|
+
cwd: directory,
|
|
170059
|
+
}, activeSessionId);
|
|
170060
|
+
break;
|
|
170061
|
+
case 'command.executed':
|
|
170062
|
+
runHook({
|
|
170063
|
+
agent: 'opencode',
|
|
170064
|
+
hook_event_name: 'command.executed',
|
|
170065
|
+
command: properties.name ?? properties.command ?? '',
|
|
170066
|
+
cwd: directory,
|
|
170067
|
+
}, activeSessionId);
|
|
170068
|
+
break;
|
|
170069
|
+
case 'message.updated': {
|
|
170070
|
+
const message = properties.info ?? properties.message ?? properties;
|
|
170071
|
+
if (message?.role !== 'assistant') break;
|
|
170072
|
+
const text = extractMessageText(message);
|
|
170073
|
+
if (!text) break;
|
|
170074
|
+
pendingAssistantResponse = { id: message.id, text };
|
|
170075
|
+
break;
|
|
170076
|
+
}
|
|
170077
|
+
case 'session.compacted':
|
|
170078
|
+
runHook({
|
|
170079
|
+
agent: 'opencode',
|
|
170080
|
+
hook_event_name: 'session.compacted',
|
|
170081
|
+
cwd: directory,
|
|
170082
|
+
}, activeSessionId);
|
|
170083
|
+
break;
|
|
170084
|
+
default:
|
|
170085
|
+
break;
|
|
170086
|
+
}
|
|
170087
|
+
}
|
|
170088
|
+
|
|
170010
170089
|
return {
|
|
170090
|
+
// OpenCode 1.x delivers lifecycle/file/command/message events through this
|
|
170091
|
+
// generic hook. The named keys below remain for older compatible hosts.
|
|
170092
|
+
event: handleEvent,
|
|
170011
170093
|
/** Session created \u2014 record session start */
|
|
170012
170094
|
'session.created': async ({ session }) => {
|
|
170013
170095
|
runHook({
|
|
@@ -170019,21 +170101,7 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
170019
170101
|
|
|
170020
170102
|
/** Session idle \u2014 record session end */
|
|
170021
170103
|
'session.idle': async ({ session }) => {
|
|
170022
|
-
|
|
170023
|
-
const deliveryKey = pendingAssistantResponse.id
|
|
170024
|
-
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
170025
|
-
: pendingAssistantResponse.text;
|
|
170026
|
-
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
170027
|
-
runHook({
|
|
170028
|
-
agent: 'opencode',
|
|
170029
|
-
hook_event_name: 'message.updated',
|
|
170030
|
-
ai_response: pendingAssistantResponse.text,
|
|
170031
|
-
message_id: pendingAssistantResponse.id,
|
|
170032
|
-
cwd: directory,
|
|
170033
|
-
});
|
|
170034
|
-
lastDeliveredAssistantKey = deliveryKey;
|
|
170035
|
-
}
|
|
170036
|
-
}
|
|
170104
|
+
flushAssistantResponse();
|
|
170037
170105
|
runHook({
|
|
170038
170106
|
agent: 'opencode',
|
|
170039
170107
|
hook_event_name: 'session.idle',
|
|
@@ -170141,7 +170209,7 @@ function v2RunHook(payload, directory, sessionId) {
|
|
|
170141
170209
|
try {
|
|
170142
170210
|
const result = spawnSync(v2HookCommand, ['hook'], {
|
|
170143
170211
|
input: JSON.stringify(nextPayload),
|
|
170144
|
-
timeout:
|
|
170212
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
170145
170213
|
encoding: 'utf-8',
|
|
170146
170214
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
170147
170215
|
shell: process.platform === 'win32',
|
|
@@ -170265,7 +170333,7 @@ function setup(ctx) {
|
|
|
170265
170333
|
return () => controller.abort();
|
|
170266
170334
|
}
|
|
170267
170335
|
|
|
170268
|
-
export default { id: 'memorix', setup };
|
|
170336
|
+
export default { id: 'memorix', server: MemorixPlugin, setup };
|
|
170269
170337
|
`;
|
|
170270
170338
|
}
|
|
170271
170339
|
async function installOpenCodeSkills(projectRoot, global2 = false) {
|
|
@@ -171091,7 +171159,7 @@ var init_installers = __esm({
|
|
|
171091
171159
|
"use strict";
|
|
171092
171160
|
init_esm_shims();
|
|
171093
171161
|
init_official_skills();
|
|
171094
|
-
OPENCODE_PLUGIN_VERSION =
|
|
171162
|
+
OPENCODE_PLUGIN_VERSION = 9;
|
|
171095
171163
|
AGENT_SKILL_DIRS = {
|
|
171096
171164
|
cursor: { project: path34.join(".cursor", "skills"), global: path34.join(".cursor", "skills") },
|
|
171097
171165
|
windsurf: { project: path34.join(".windsurf", "skills"), global: path34.join(".windsurf", "skills") },
|
|
@@ -176615,7 +176683,7 @@ var init_serve_shared = __esm({
|
|
|
176615
176683
|
|
|
176616
176684
|
// src/cli/version.ts
|
|
176617
176685
|
function getCliVersion() {
|
|
176618
|
-
return true ? "1.9.
|
|
176686
|
+
return true ? "1.9.10" : pkg.version;
|
|
176619
176687
|
}
|
|
176620
176688
|
var init_version3 = __esm({
|
|
176621
176689
|
"src/cli/version.ts"() {
|
|
@@ -6,6 +6,15 @@ All notable changes to this project will be documented in this file.
|
|
|
6
6
|
|
|
7
7
|
No unreleased changes.
|
|
8
8
|
|
|
9
|
+
## [1.9.10] - 2026-10-08
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- **OpenCode 1.x regression** -- generated plugins now include the v1
|
|
13
|
+
`server` field alongside the v2 `setup` contract, so OpenCode 1.x can load
|
|
14
|
+
the legacy named export. Lifecycle, file, command, message, and compaction
|
|
15
|
+
events are also forwarded through the v1 generic `event` hook, with a longer
|
|
16
|
+
Windows hook timeout to reduce stale Bun timer failures.
|
|
17
|
+
|
|
9
18
|
## [1.9.9] - 2026-10-02
|
|
10
19
|
|
|
11
20
|
### Added
|
package/dist/sdk.js
CHANGED
|
@@ -165923,6 +165923,8 @@ function generateOpenCodePlugin() {
|
|
|
165923
165923
|
*/
|
|
165924
165924
|
import { spawnSync } from 'node:child_process';
|
|
165925
165925
|
|
|
165926
|
+
const HOOK_TIMEOUT_MS = 30_000;
|
|
165927
|
+
|
|
165926
165928
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
165927
165929
|
// Generate a stable session ID for this plugin lifetime
|
|
165928
165930
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
@@ -165948,14 +165950,14 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
165948
165950
|
* - spawnSync is simpler: no stream lifecycle, no writer.close() bugs
|
|
165949
165951
|
* - stdin pipe via input option is reliable cross-platform
|
|
165950
165952
|
*/
|
|
165951
|
-
function runHook(payload) {
|
|
165952
|
-
payload.session_id =
|
|
165953
|
+
function runHook(payload, activeSessionId = sessionId) {
|
|
165954
|
+
payload.session_id = activeSessionId;
|
|
165953
165955
|
const data = JSON.stringify(payload);
|
|
165954
165956
|
const eventName = payload.hook_event_name || 'unknown';
|
|
165955
165957
|
try {
|
|
165956
165958
|
const result = spawnSync(hookCommand, ['hook'], {
|
|
165957
165959
|
input: data,
|
|
165958
|
-
timeout:
|
|
165960
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
165959
165961
|
encoding: 'utf-8',
|
|
165960
165962
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
165961
165963
|
shell: process.platform === 'win32',
|
|
@@ -166000,7 +166002,87 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
166000
166002
|
.trim();
|
|
166001
166003
|
}
|
|
166002
166004
|
|
|
166005
|
+
function flushAssistantResponse(activeSessionId = sessionId) {
|
|
166006
|
+
if (!pendingAssistantResponse?.text) return;
|
|
166007
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
166008
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
166009
|
+
: pendingAssistantResponse.text;
|
|
166010
|
+
if (deliveryKey === lastDeliveredAssistantKey) return;
|
|
166011
|
+
runHook({
|
|
166012
|
+
agent: 'opencode',
|
|
166013
|
+
hook_event_name: 'message.updated',
|
|
166014
|
+
ai_response: pendingAssistantResponse.text,
|
|
166015
|
+
message_id: pendingAssistantResponse.id,
|
|
166016
|
+
cwd: directory,
|
|
166017
|
+
}, activeSessionId);
|
|
166018
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
166019
|
+
}
|
|
166020
|
+
|
|
166021
|
+
function eventSessionId(event) {
|
|
166022
|
+
const properties = event?.properties ?? {};
|
|
166023
|
+
const value = properties.sessionID ?? properties.sessionId ?? properties.info?.id;
|
|
166024
|
+
return typeof value === 'string' && value ? value : sessionId;
|
|
166025
|
+
}
|
|
166026
|
+
|
|
166027
|
+
async function handleEvent({ event }) {
|
|
166028
|
+
const properties = event?.properties ?? {};
|
|
166029
|
+
const activeSessionId = eventSessionId(event);
|
|
166030
|
+
switch (event?.type) {
|
|
166031
|
+
case 'session.created':
|
|
166032
|
+
runHook({
|
|
166033
|
+
agent: 'opencode',
|
|
166034
|
+
hook_event_name: 'session.created',
|
|
166035
|
+
cwd: directory,
|
|
166036
|
+
}, activeSessionId);
|
|
166037
|
+
break;
|
|
166038
|
+
case 'session.idle':
|
|
166039
|
+
flushAssistantResponse(activeSessionId);
|
|
166040
|
+
runHook({
|
|
166041
|
+
agent: 'opencode',
|
|
166042
|
+
hook_event_name: 'session.idle',
|
|
166043
|
+
cwd: directory,
|
|
166044
|
+
}, activeSessionId);
|
|
166045
|
+
break;
|
|
166046
|
+
case 'file.edited':
|
|
166047
|
+
runHook({
|
|
166048
|
+
agent: 'opencode',
|
|
166049
|
+
hook_event_name: 'file.edited',
|
|
166050
|
+
file_path: properties.file ?? properties.path ?? '',
|
|
166051
|
+
cwd: directory,
|
|
166052
|
+
}, activeSessionId);
|
|
166053
|
+
break;
|
|
166054
|
+
case 'command.executed':
|
|
166055
|
+
runHook({
|
|
166056
|
+
agent: 'opencode',
|
|
166057
|
+
hook_event_name: 'command.executed',
|
|
166058
|
+
command: properties.name ?? properties.command ?? '',
|
|
166059
|
+
cwd: directory,
|
|
166060
|
+
}, activeSessionId);
|
|
166061
|
+
break;
|
|
166062
|
+
case 'message.updated': {
|
|
166063
|
+
const message = properties.info ?? properties.message ?? properties;
|
|
166064
|
+
if (message?.role !== 'assistant') break;
|
|
166065
|
+
const text = extractMessageText(message);
|
|
166066
|
+
if (!text) break;
|
|
166067
|
+
pendingAssistantResponse = { id: message.id, text };
|
|
166068
|
+
break;
|
|
166069
|
+
}
|
|
166070
|
+
case 'session.compacted':
|
|
166071
|
+
runHook({
|
|
166072
|
+
agent: 'opencode',
|
|
166073
|
+
hook_event_name: 'session.compacted',
|
|
166074
|
+
cwd: directory,
|
|
166075
|
+
}, activeSessionId);
|
|
166076
|
+
break;
|
|
166077
|
+
default:
|
|
166078
|
+
break;
|
|
166079
|
+
}
|
|
166080
|
+
}
|
|
166081
|
+
|
|
166003
166082
|
return {
|
|
166083
|
+
// OpenCode 1.x delivers lifecycle/file/command/message events through this
|
|
166084
|
+
// generic hook. The named keys below remain for older compatible hosts.
|
|
166085
|
+
event: handleEvent,
|
|
166004
166086
|
/** Session created \u2014 record session start */
|
|
166005
166087
|
'session.created': async ({ session }) => {
|
|
166006
166088
|
runHook({
|
|
@@ -166012,21 +166094,7 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
166012
166094
|
|
|
166013
166095
|
/** Session idle \u2014 record session end */
|
|
166014
166096
|
'session.idle': async ({ session }) => {
|
|
166015
|
-
|
|
166016
|
-
const deliveryKey = pendingAssistantResponse.id
|
|
166017
|
-
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
166018
|
-
: pendingAssistantResponse.text;
|
|
166019
|
-
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
166020
|
-
runHook({
|
|
166021
|
-
agent: 'opencode',
|
|
166022
|
-
hook_event_name: 'message.updated',
|
|
166023
|
-
ai_response: pendingAssistantResponse.text,
|
|
166024
|
-
message_id: pendingAssistantResponse.id,
|
|
166025
|
-
cwd: directory,
|
|
166026
|
-
});
|
|
166027
|
-
lastDeliveredAssistantKey = deliveryKey;
|
|
166028
|
-
}
|
|
166029
|
-
}
|
|
166097
|
+
flushAssistantResponse();
|
|
166030
166098
|
runHook({
|
|
166031
166099
|
agent: 'opencode',
|
|
166032
166100
|
hook_event_name: 'session.idle',
|
|
@@ -166134,7 +166202,7 @@ function v2RunHook(payload, directory, sessionId) {
|
|
|
166134
166202
|
try {
|
|
166135
166203
|
const result = spawnSync(v2HookCommand, ['hook'], {
|
|
166136
166204
|
input: JSON.stringify(nextPayload),
|
|
166137
|
-
timeout:
|
|
166205
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
166138
166206
|
encoding: 'utf-8',
|
|
166139
166207
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
166140
166208
|
shell: process.platform === 'win32',
|
|
@@ -166258,7 +166326,7 @@ function setup(ctx) {
|
|
|
166258
166326
|
return () => controller.abort();
|
|
166259
166327
|
}
|
|
166260
166328
|
|
|
166261
|
-
export default { id: 'memorix', setup };
|
|
166329
|
+
export default { id: 'memorix', server: MemorixPlugin, setup };
|
|
166262
166330
|
`;
|
|
166263
166331
|
}
|
|
166264
166332
|
async function installOpenCodeSkills(projectRoot, global2 = false) {
|
|
@@ -167084,7 +167152,7 @@ var init_installers = __esm({
|
|
|
167084
167152
|
"use strict";
|
|
167085
167153
|
init_esm_shims();
|
|
167086
167154
|
init_official_skills();
|
|
167087
|
-
OPENCODE_PLUGIN_VERSION =
|
|
167155
|
+
OPENCODE_PLUGIN_VERSION = 9;
|
|
167088
167156
|
AGENT_SKILL_DIRS = {
|
|
167089
167157
|
cursor: { project: path34.join(".cursor", "skills"), global: path34.join(".cursor", "skills") },
|
|
167090
167158
|
windsurf: { project: path34.join(".windsurf", "skills"), global: path34.join(".windsurf", "skills") },
|
|
@@ -170989,7 +171057,7 @@ var MCP_SERVER_INFO_META_KEY = "io.modelcontextprotocol/serverInfo";
|
|
|
170989
171057
|
function getMcpServerInfo() {
|
|
170990
171058
|
return {
|
|
170991
171059
|
name: "memorix",
|
|
170992
|
-
version: true ? "1.9.
|
|
171060
|
+
version: true ? "1.9.10" : "1.0.1"
|
|
170993
171061
|
};
|
|
170994
171062
|
}
|
|
170995
171063
|
function createMcpDiscoverResult(capabilities, serverInfo) {
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -13,7 +13,7 @@ Memorix is a TypeScript project built around:
|
|
|
13
13
|
|
|
14
14
|
## Current Development Baseline
|
|
15
15
|
|
|
16
|
-
The current release line is **1.9.
|
|
16
|
+
The current release line is **1.9.10** and package metadata is kept synchronized
|
|
17
17
|
with the root package and MCP Registry manifest.
|
|
18
18
|
|
|
19
19
|
Contributors should assume the following areas are part of the current release line:
|
package/docs/INTEGRATIONS.md
CHANGED
|
@@ -55,7 +55,7 @@ Generated guidance also has scope:
|
|
|
55
55
|
| Cursor | `memorix setup --agent cursor --global` | Cursor MCP and rules config | Cursor MCP config, `.cursor/rules/memorix.mdc`, skills, and hook guidance | Reload Cursor after setup so it can pick up project config changes. |
|
|
56
56
|
| Grok Build | `memorix setup --agent grok --global` | `~/.grok/hooks/memorix.json` + `~/.grok/AGENTS.md` | Lifecycle hooks on SessionStart, SessionEnd, UserPromptSubmit, PostToolUse, PostToolUseFailure, PreCompact, PostCompact, Stop, and StopFailure, plus Grok project/global guidance | Uses Grok's own JSON hook directory. MCP stays host-owned unless you pass `--mcp http`, which writes `[mcp_servers.memorix]` with `url = "http://localhost:3211/mcp"` in Grok `config.toml`. Global hooks are trusted; project hooks require Grok `/hooks-trust`. Set `GROK_HOME` to use a custom Grok home. The command is `memorix hook --agent grok`. |
|
|
57
57
|
| Gemini CLI | `memorix setup --agent gemini-cli --global` | Gemini CLI extension | Extension under `~/.gemini/extensions/memorix` with MCP, `GEMINI.md` context, hooks, commands, and skills | Antigravity CLI has an official Gemini CLI migration path, but Gemini CLI remains an active standalone Google CLI target. |
|
|
58
|
-
| OpenCode | `memorix setup --agent opencode --global` | OpenCode local plugin file | Global setup writes `~/.config/opencode/plugins/memorix.js`, `~/.config/opencode/opencode.json`, skills, and `AGENTS.md` guidance; repo-local setup writes the `.opencode/` equivalents. | The generated plugin keeps the v1 named export and
|
|
58
|
+
| OpenCode | `memorix setup --agent opencode --global` | OpenCode local plugin file | Global setup writes `~/.config/opencode/plugins/memorix.js`, `~/.config/opencode/opencode.json`, skills, and `AGENTS.md` guidance; repo-local setup writes the `.opencode/` equivalents. | The generated plugin keeps the v1 named export, adds the v1 `server` field to its dual default export, and exposes the v2 `id`/`setup` contract. OpenCode 1.x lifecycle/file/command/message events use the generic `event` hook; v2 subscriptions use the host session ID when forwarding hooks. |
|
|
59
59
|
| OpenClaw | `memorix setup --agent openclaw --global` | OpenClaw compatible bundle | `~/.openclaw/extensions/memorix` with `.mcp.json`, skills, and OpenClaw `HOOK.md`/`handler.ts` hook pack | Setup attempts `openclaw plugins install <path> --force` and `openclaw hooks enable memorix` when OpenClaw is available. |
|
|
60
60
|
| Hermes Agent | `memorix setup --agent hermes --global` | Hermes plugin | Hermes home (`%LOCALAPPDATA%\hermes` on native Windows, `~/.hermes` elsewhere, or `HERMES_HOME`), plugin enablement in `config.yaml`, and `mcp_servers.memorix` | The plugin registers hooks, a slash command, a CLI command, and skills through Hermes' plugin context. Existing YAML keys are preserved. |
|
|
61
61
|
| Oh-my-Pi | `memorix setup --agent omp --global` | Oh-my-Pi `omp.extensions` package | `.omp/packages/memorix` or `~/.omp/agent/packages/memorix`, plus `.omp/mcp.json` or `~/.omp/agent/mcp.json` | Setup attempts `omp plugin link <path>`. This target uses Oh-my-Pi's package/extension manifest, not Pi's legacy package manifest. |
|
package/docs/README.md
CHANGED
|
@@ -126,7 +126,7 @@ Historical/deep-reference documents may describe older designs. If they conflict
|
|
|
126
126
|
|
|
127
127
|
## Current Product Line
|
|
128
128
|
|
|
129
|
-
The current product line is **1.9.
|
|
129
|
+
The current product line is **1.9.10**. Multi-device store sync is opt-in and
|
|
130
130
|
keeps local SQLite canonical; existing users do not upload anything until they
|
|
131
131
|
configure a relay provider explicitly.
|
|
132
132
|
The authoritative acceptance contract for the current implementation is
|
package/docs/SETUP.md
CHANGED
|
@@ -502,7 +502,7 @@ OpenCode can also use a local Memorix plugin generated by setup:
|
|
|
502
502
|
memorix setup --agent opencode --global
|
|
503
503
|
```
|
|
504
504
|
|
|
505
|
-
This writes the OpenCode plugin, skills, MCP config, and `AGENTS.md` guidance in the selected scope. The generated plugin exports
|
|
505
|
+
This writes the OpenCode plugin, skills, MCP config, and `AGENTS.md` guidance in the selected scope. The generated plugin exports the legacy v1 hook function and a dual default object with the v1 `server` field plus the v2 `id`/`setup` contract, so OpenCode v1 and v2 can load the same file during the migration window. OpenCode 1.x events are received through its generic `event` hook.
|
|
506
506
|
|
|
507
507
|
Antigravity setup installs a native plugin at `~/.gemini/config/plugins/memorix` for global setup or `.agents/plugins/memorix` for workspace setup. The plugin includes stdio MCP, official hooks, rules, and skills:
|
|
508
508
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorix",
|
|
3
3
|
"mcpName": "io.github.AVIDS2/memorix",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.10",
|
|
5
5
|
"description": "Local-first shared memory layer for AI coding agents across MCP clients, Git history, reasoning context, and project sessions.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
package/server.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/AVIDS2/memorix",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "1.9.
|
|
10
|
+
"version": "1.9.10",
|
|
11
11
|
"websiteUrl": "https://mem.rglens.com",
|
|
12
12
|
"icons": [
|
|
13
13
|
{
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
{
|
|
23
23
|
"registryType": "npm",
|
|
24
24
|
"identifier": "memorix",
|
|
25
|
-
"version": "1.9.
|
|
25
|
+
"version": "1.9.10",
|
|
26
26
|
"runtimeHint": "npx",
|
|
27
27
|
"packageArguments": [
|
|
28
28
|
{
|
|
@@ -466,7 +466,7 @@ function generateKiroHookFiles(): Array<{ filename: string; content: string }> {
|
|
|
466
466
|
* protocol used by all agents. spawnSync works in both Node.js and Bun
|
|
467
467
|
* runtimes (OpenCode may fall back to Node.js on Windows).
|
|
468
468
|
*/
|
|
469
|
-
const OPENCODE_PLUGIN_VERSION =
|
|
469
|
+
const OPENCODE_PLUGIN_VERSION = 9;
|
|
470
470
|
|
|
471
471
|
const AGENT_SKILL_DIRS: Partial<Record<AgentName, { project: string; global?: string }>> = {
|
|
472
472
|
cursor: { project: path.join('.cursor', 'skills'), global: path.join('.cursor', 'skills') },
|
|
@@ -537,6 +537,8 @@ function generateOpenCodePlugin(): string {
|
|
|
537
537
|
*/
|
|
538
538
|
import { spawnSync } from 'node:child_process';
|
|
539
539
|
|
|
540
|
+
const HOOK_TIMEOUT_MS = 30_000;
|
|
541
|
+
|
|
540
542
|
export const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
541
543
|
// Generate a stable session ID for this plugin lifetime
|
|
542
544
|
const sessionId = \`opencode-\${Date.now().toString(36)}-\${Math.random().toString(36).slice(2, 8)}\`;
|
|
@@ -562,14 +564,14 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
562
564
|
* - spawnSync is simpler: no stream lifecycle, no writer.close() bugs
|
|
563
565
|
* - stdin pipe via input option is reliable cross-platform
|
|
564
566
|
*/
|
|
565
|
-
function runHook(payload) {
|
|
566
|
-
payload.session_id =
|
|
567
|
+
function runHook(payload, activeSessionId = sessionId) {
|
|
568
|
+
payload.session_id = activeSessionId;
|
|
567
569
|
const data = JSON.stringify(payload);
|
|
568
570
|
const eventName = payload.hook_event_name || 'unknown';
|
|
569
571
|
try {
|
|
570
572
|
const result = spawnSync(hookCommand, ['hook'], {
|
|
571
573
|
input: data,
|
|
572
|
-
timeout:
|
|
574
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
573
575
|
encoding: 'utf-8',
|
|
574
576
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
575
577
|
shell: process.platform === 'win32',
|
|
@@ -614,7 +616,87 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
614
616
|
.trim();
|
|
615
617
|
}
|
|
616
618
|
|
|
619
|
+
function flushAssistantResponse(activeSessionId = sessionId) {
|
|
620
|
+
if (!pendingAssistantResponse?.text) return;
|
|
621
|
+
const deliveryKey = pendingAssistantResponse.id
|
|
622
|
+
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
623
|
+
: pendingAssistantResponse.text;
|
|
624
|
+
if (deliveryKey === lastDeliveredAssistantKey) return;
|
|
625
|
+
runHook({
|
|
626
|
+
agent: 'opencode',
|
|
627
|
+
hook_event_name: 'message.updated',
|
|
628
|
+
ai_response: pendingAssistantResponse.text,
|
|
629
|
+
message_id: pendingAssistantResponse.id,
|
|
630
|
+
cwd: directory,
|
|
631
|
+
}, activeSessionId);
|
|
632
|
+
lastDeliveredAssistantKey = deliveryKey;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function eventSessionId(event) {
|
|
636
|
+
const properties = event?.properties ?? {};
|
|
637
|
+
const value = properties.sessionID ?? properties.sessionId ?? properties.info?.id;
|
|
638
|
+
return typeof value === 'string' && value ? value : sessionId;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
async function handleEvent({ event }) {
|
|
642
|
+
const properties = event?.properties ?? {};
|
|
643
|
+
const activeSessionId = eventSessionId(event);
|
|
644
|
+
switch (event?.type) {
|
|
645
|
+
case 'session.created':
|
|
646
|
+
runHook({
|
|
647
|
+
agent: 'opencode',
|
|
648
|
+
hook_event_name: 'session.created',
|
|
649
|
+
cwd: directory,
|
|
650
|
+
}, activeSessionId);
|
|
651
|
+
break;
|
|
652
|
+
case 'session.idle':
|
|
653
|
+
flushAssistantResponse(activeSessionId);
|
|
654
|
+
runHook({
|
|
655
|
+
agent: 'opencode',
|
|
656
|
+
hook_event_name: 'session.idle',
|
|
657
|
+
cwd: directory,
|
|
658
|
+
}, activeSessionId);
|
|
659
|
+
break;
|
|
660
|
+
case 'file.edited':
|
|
661
|
+
runHook({
|
|
662
|
+
agent: 'opencode',
|
|
663
|
+
hook_event_name: 'file.edited',
|
|
664
|
+
file_path: properties.file ?? properties.path ?? '',
|
|
665
|
+
cwd: directory,
|
|
666
|
+
}, activeSessionId);
|
|
667
|
+
break;
|
|
668
|
+
case 'command.executed':
|
|
669
|
+
runHook({
|
|
670
|
+
agent: 'opencode',
|
|
671
|
+
hook_event_name: 'command.executed',
|
|
672
|
+
command: properties.name ?? properties.command ?? '',
|
|
673
|
+
cwd: directory,
|
|
674
|
+
}, activeSessionId);
|
|
675
|
+
break;
|
|
676
|
+
case 'message.updated': {
|
|
677
|
+
const message = properties.info ?? properties.message ?? properties;
|
|
678
|
+
if (message?.role !== 'assistant') break;
|
|
679
|
+
const text = extractMessageText(message);
|
|
680
|
+
if (!text) break;
|
|
681
|
+
pendingAssistantResponse = { id: message.id, text };
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
case 'session.compacted':
|
|
685
|
+
runHook({
|
|
686
|
+
agent: 'opencode',
|
|
687
|
+
hook_event_name: 'session.compacted',
|
|
688
|
+
cwd: directory,
|
|
689
|
+
}, activeSessionId);
|
|
690
|
+
break;
|
|
691
|
+
default:
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
617
696
|
return {
|
|
697
|
+
// OpenCode 1.x delivers lifecycle/file/command/message events through this
|
|
698
|
+
// generic hook. The named keys below remain for older compatible hosts.
|
|
699
|
+
event: handleEvent,
|
|
618
700
|
/** Session created — record session start */
|
|
619
701
|
'session.created': async ({ session }) => {
|
|
620
702
|
runHook({
|
|
@@ -626,21 +708,7 @@ export const MemorixPlugin = async ({ project, client, $, directory, worktree })
|
|
|
626
708
|
|
|
627
709
|
/** Session idle — record session end */
|
|
628
710
|
'session.idle': async ({ session }) => {
|
|
629
|
-
|
|
630
|
-
const deliveryKey = pendingAssistantResponse.id
|
|
631
|
-
? \`\${pendingAssistantResponse.id}:\${pendingAssistantResponse.text}\`
|
|
632
|
-
: pendingAssistantResponse.text;
|
|
633
|
-
if (deliveryKey !== lastDeliveredAssistantKey) {
|
|
634
|
-
runHook({
|
|
635
|
-
agent: 'opencode',
|
|
636
|
-
hook_event_name: 'message.updated',
|
|
637
|
-
ai_response: pendingAssistantResponse.text,
|
|
638
|
-
message_id: pendingAssistantResponse.id,
|
|
639
|
-
cwd: directory,
|
|
640
|
-
});
|
|
641
|
-
lastDeliveredAssistantKey = deliveryKey;
|
|
642
|
-
}
|
|
643
|
-
}
|
|
711
|
+
flushAssistantResponse();
|
|
644
712
|
runHook({
|
|
645
713
|
agent: 'opencode',
|
|
646
714
|
hook_event_name: 'session.idle',
|
|
@@ -748,7 +816,7 @@ function v2RunHook(payload, directory, sessionId) {
|
|
|
748
816
|
try {
|
|
749
817
|
const result = spawnSync(v2HookCommand, ['hook'], {
|
|
750
818
|
input: JSON.stringify(nextPayload),
|
|
751
|
-
timeout:
|
|
819
|
+
timeout: HOOK_TIMEOUT_MS,
|
|
752
820
|
encoding: 'utf-8',
|
|
753
821
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
754
822
|
shell: process.platform === 'win32',
|
|
@@ -872,7 +940,7 @@ function setup(ctx) {
|
|
|
872
940
|
return () => controller.abort();
|
|
873
941
|
}
|
|
874
942
|
|
|
875
|
-
export default { id: 'memorix', setup };
|
|
943
|
+
export default { id: 'memorix', server: MemorixPlugin, setup };
|
|
876
944
|
`;
|
|
877
945
|
}
|
|
878
946
|
|