toolnet-memory 0.3.3 → 0.3.5
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/bundle/agy-hook.js +79 -69
- package/bundle/agy.js +71 -61
- package/bundle/api.js +16 -16
- package/bundle/auto-integrate.js +377 -71
- package/bundle/claude-hook.js +102 -36
- package/bundle/codex-context.js +10 -10
- package/bundle/codex.js +67 -65
- package/bundle/context-runtime.js +30 -30
- package/bundle/context.js +15 -15
- package/bundle/continuity-certify.js +14 -13
- package/bundle/doctor.js +5 -5
- package/bundle/full-index.js +22 -18
- package/bundle/graph-index.js +2 -2
- package/bundle/handoff-refresh.js +7 -7
- package/bundle/init.js +386 -80
- package/bundle/learner.js +1 -1
- package/bundle/mcp.js +19 -19
- package/bundle/memory-agent.js +11 -11
- package/bundle/memory-query.js +5 -5
- package/bundle/opencode.js +442 -121
- package/bundle/project-manual.js +3 -3
- package/bundle/provider.js +5 -2
- package/bundle/recovery-certify.js +21 -20
- package/bundle/runtime.js +4 -4
- package/bundle/semantic.js +5 -5
- package/bundle/service-cli.js +2 -2
- package/bundle/setup.js +376 -70
- package/bundle/snapshot.js +4 -4
- package/bundle/update.js +4 -4
- package/bundle/work-continuity.js +7 -7
- package/package.json +1 -1
package/bundle/auto-integrate.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{existsSync as
|
|
2
|
-
`,{encoding:"utf8",mode:384}),
|
|
3
|
-
`,{encoding:"utf8",mode:384}),
|
|
1
|
+
import{existsSync as je}from"node:fs";import{homedir as Ae}from"node:os";import{join as Me}from"node:path";import{spawnSync as Fe}from"node:child_process";import{homedir as Te}from"node:os";import{join as p}from"node:path";function _(e={}){return p(e.home??Te(),".gemini")}function I(e={}){return p(_(e),"config")}function x(e={}){return p(I(e),"mcp_config.json")}function C(e={}){return p(I(e),"hooks.json")}function P(e={}){return p(_(e),"antigravity-cli")}function J(e="toolnet-memory",n={}){return p(P(n),"plugins",e)}function D(e={}){return[P(e),I(e)]}import{homedir as Ee}from"node:os";import{join as y}from"node:path";function m(e={}){let n=e.xdgConfigHome??process.env.XDG_CONFIG_HOME?.trim();return n?y(n,"opencode"):y(e.home??Ee(),".config","opencode")}function $(e={}){return y(m(e),"opencode.json")}function L(e={}){return y(m(e),"plugins")}function H(e={}){return y(m(e),"AGENTS.md")}import{homedir as B}from"node:os";import{join as k}from"node:path";function N(e={}){return k(e.home??B(),".claude")}function U(e={}){return k(N(e),"settings.json")}function Y(e={}){return k(e.home??B(),".claude.json")}function Re(e){return Fe("sh",["-lc",`command -v ${JSON.stringify(e)} >/dev/null 2>&1`],{stdio:"ignore"}).status===0}function S(e){let n=e.commandExists(e.command),t=e.configPaths.filter(s=>je(s)),o=t.length>0,i=[];n&&i.push(`command:${e.command}`);for(let s of t)i.push(`config:${s}`);return{agent:e.agent,detected:n||o,commandDetected:n,configDetected:o,evidence:i}}function q(e={}){let n=e.home??Ae(),t=e.commandExists??Re,o=e.codexHome??process.env.CODEX_HOME??Me(n,".codex");return[S({agent:"agy",command:"agy",commandExists:t,configPaths:D({home:n})}),S({agent:"opencode",command:"opencode",commandExists:t,configPaths:[m({home:n,xdgConfigHome:e.xdgConfigHome})]}),S({agent:"claude",command:"claude",commandExists:t,configPaths:[N({home:n})]}),S({agent:"codex",command:"codex",commandExists:t,configPaths:[o]})]}import{existsSync as w,mkdirSync as z,readFileSync as Q,renameSync as Ve,writeFileSync as ze}from"node:fs";import{dirname as Qe,join as b}from"node:path";import{existsSync as _e,mkdirSync as Pe,readFileSync as Je,renameSync as De,rmSync as $e,writeFileSync as Le}from"node:fs";import{dirname as He}from"node:path";function Be(e){return`'${e.replace(/'/g,"'\\''")}'`}function W(e={}){let n=e.hooksFile??C();Pe(He(n),{recursive:!0,mode:448});let t={};if(_e(n)){let r;try{r=JSON.parse(Je(n,"utf8"))}catch(c){throw new Error(`Invalid existing Agy hooks.json: ${c instanceof Error?c.message:String(c)}`)}if(typeof r!="object"||r===null||Array.isArray(r))throw new Error("Invalid existing Agy hooks.json: root must be a JSON object.");t=r}let o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",i=`${Be(o)} session:agy-hook`;t["toolnet-memory"]={enabled:!0,PreToolUse:[{matcher:"view_file|list_dir|find_by_name|grep_search|run_command",hooks:[{type:"command",command:`${i} pre-tool`,timeout:5}]}],PreInvocation:[{type:"command",command:`${i} pre`,timeout:15}],PostInvocation:[{type:"command",command:`${i} post`,timeout:15}],Stop:[{type:"command",command:`${i} stop`,timeout:30}]};let s=`${n}.tmp-${process.pid}-${Date.now()}`;try{Le(s,JSON.stringify(t,null,2)+`
|
|
2
|
+
`,{encoding:"utf8",mode:384}),De(s,n)}finally{$e(s,{force:!0})}return n}import{existsSync as Ue,mkdirSync as Ye,readFileSync as qe,renameSync as We,writeFileSync as Ge}from"node:fs";import{dirname as Xe}from"node:path";function h(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Ke(e,n){Ye(Xe(e),{recursive:!0,mode:448});let t=`${e}.tmp-${process.pid}-${Date.now()}`;Ge(t,`${JSON.stringify(n,null,2)}
|
|
3
|
+
`,{encoding:"utf8",mode:384}),We(t,e)}function G(e){if(!Ue(e))return{};let n=qe(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid existing Agy MCP config: ${o instanceof Error?o.message:String(o)}`)}if(!h(t))throw new Error("Invalid existing Agy MCP config: root must be a JSON object.");return t}function X(e,n){return h(e)?e.command===n&&Array.isArray(e.args)&&e.args.length===1&&e.args[0]==="mcp":!1}function K(e={}){let n=e.configFile??x(),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",i=G(n),s=i.mcpServers;if(s!==void 0&&!h(s))throw new Error("Invalid existing Agy MCP config: mcpServers must be an object.");let r=h(s)?{...s}:{},c=r[o];if(X(c,t))return{installed:!0,changed:!1,configFile:n,serverName:o,command:t,args:["mcp"]};r[o]={command:t,args:["mcp"]};let l={...i,mcpServers:r};Ke(n,l);let a=G(n).mcpServers;if(!h(a)||!X(a[o],t))throw new Error("Agy MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:n,serverName:o,command:t,args:["mcp"]}}var Ze=`# ToolNet Memory Continuity
|
|
4
4
|
|
|
5
5
|
ToolNet Memory is the authoritative continuity layer for previous project work.
|
|
6
6
|
|
|
@@ -41,11 +41,11 @@ Use \`mode="ai"\` only when continuity is ambiguous or requires synthesis.
|
|
|
41
41
|
Current repository evidence overrides stale memory after ToolNet has restored the working context.
|
|
42
42
|
|
|
43
43
|
Do not ask the user to repeat context already available through ToolNet Memory.
|
|
44
|
-
`;function Z(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function
|
|
45
|
-
`),!0}function tt(e){if(!w(e))return!1;let n=ee(e);if(!Object.prototype.hasOwnProperty.call(n,"toolnet-memory"))return!1;let t={...n};return delete t["toolnet-memory"],
|
|
46
|
-
`),!0}function te(e={}){let n=e.pluginName??"toolnet-memory",t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.pluginRoot
|
|
47
|
-
`),
|
|
48
|
-
`);let l=e.legacyMcpFile??
|
|
44
|
+
`;function Z(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function T(e,n){z(Qe(e),{recursive:!0});let t=`${e}.tmp-${process.pid}-${Date.now()}`;ze(t,n,{encoding:"utf8",mode:384}),Ve(t,e)}function V(e,n){w(e)&&Q(e,"utf8")===n||T(e,n)}function ee(e){if(!w(e))return{};let n=Q(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid legacy Antigravity config ${e}: ${o instanceof Error?o.message:String(o)}`)}if(!Z(t))throw new Error(`Invalid legacy Antigravity config ${e}: root must be object`);return t}function et(e,n){if(!w(e))return!1;let t=ee(e);if(!Z(t.mcpServers)||!Object.prototype.hasOwnProperty.call(t.mcpServers,n))return!1;let o={...t.mcpServers};return delete o[n],T(e,`${JSON.stringify({...t,mcpServers:o},null,2)}
|
|
45
|
+
`),!0}function tt(e){if(!w(e))return!1;let n=ee(e);if(!Object.prototype.hasOwnProperty.call(n,"toolnet-memory"))return!1;let t={...n};return delete t["toolnet-memory"],T(e,`${JSON.stringify(t,null,2)}
|
|
46
|
+
`),!0}function te(e={}){let n=e.pluginName??"toolnet-memory",t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.pluginRoot??J(n),i=b(o,"plugin.json"),s=b(o,"mcp_config.json"),r=b(o,"hooks.json"),c=b(o,"rules","toolnet-memory-continuity.md");z(o,{recursive:!0,mode:448}),V(i,`${JSON.stringify({$schema:"https://antigravity.google/schemas/v1/plugin.json",name:n,description:"Persistent project continuity and memory for Antigravity coding sessions."},null,2)}
|
|
47
|
+
`),K({configFile:s,binary:t,serverName:"toolnet-memory"}),W({hooksFile:r,binary:t}),V(c,`${Ze.trim()}
|
|
48
|
+
`);let l=e.legacyMcpFile??x(),u=e.legacyHooksFile??C(),a=[];return l!==s&&et(l,"toolnet-memory")&&a.push(l),u!==r&&tt(u)&&a.push(u),{installed:!0,pluginRoot:o,files:[i,s,r,c],migratedLegacy:a}}import{existsSync as ot,mkdirSync as re,readFileSync as rt,writeFileSync as se}from"node:fs";import{join as st}from"node:path";var nt="memory_agent_ask";function ne(){return`
|
|
49
49
|
[TOOLNET MEMORY AGENT]
|
|
50
50
|
|
|
51
51
|
Tool available:
|
|
@@ -96,7 +96,7 @@ Rules:
|
|
|
96
96
|
- After receiving the ToolNet answer, continue the task
|
|
97
97
|
instead of asking the user to repeat known context.
|
|
98
98
|
- If ToolNet says information is not recorded, say so.
|
|
99
|
-
`.trim()}var oe="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",E="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function it(){let e=
|
|
99
|
+
`.trim()}var oe="<!-- TOOLNET_MEMORY_BOOTSTRAP_START -->",E="<!-- TOOLNET_MEMORY_BOOTSTRAP_END -->";function it(){let e=H();re(m(),{recursive:!0});let n=`${oe}
|
|
100
100
|
## ToolNet Memory
|
|
101
101
|
|
|
102
102
|
ToolNet Memory is available for projects that already contain a valid \`.toolnet/project.json\`.
|
|
@@ -117,7 +117,7 @@ ${ne()}
|
|
|
117
117
|
${E}`,t=ot(e)?rt(e,"utf8"):"",o=t.indexOf(oe),i=t.indexOf(E);return o>=0&&i>=o?t=t.slice(0,o)+n+t.slice(i+E.length):(t=t.trimEnd(),t&&(t+=`
|
|
118
118
|
|
|
119
119
|
`),t+=n),se(e,t.trimEnd()+`
|
|
120
|
-
`,{encoding:"utf8",mode:384}),e}function ie(e={}){let n=e.directory??
|
|
120
|
+
`,{encoding:"utf8",mode:384}),e}function ie(e={}){let n=e.directory??L();re(n,{recursive:!0}),it();let t=st(n,"toolnet-memory.js"),o=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",i=`
|
|
121
121
|
// Generated by ToolNet Memory.
|
|
122
122
|
// OpenCode integration:
|
|
123
123
|
// - project gated
|
|
@@ -137,22 +137,52 @@ const CONTEXT_MAX_TOKENS = 700
|
|
|
137
137
|
|
|
138
138
|
const CONTEXT_CACHE_MS = 5000
|
|
139
139
|
|
|
140
|
-
const
|
|
140
|
+
const LOCAL_CAPTURE_MS = 15000
|
|
141
141
|
|
|
142
|
-
const
|
|
142
|
+
const REMOTE_SYNC_MS = 60000
|
|
143
143
|
|
|
144
|
-
const
|
|
144
|
+
const EVENT_CAPTURE_DEBOUNCE_MS = 1200
|
|
145
|
+
|
|
146
|
+
const CAPTURE_TIMEOUT_MS = 20000
|
|
147
|
+
|
|
148
|
+
const REMOTE_TIMEOUT_MS = 120000
|
|
149
|
+
|
|
150
|
+
const GLOBAL_STATUS_FILE = path.join(
|
|
145
151
|
os.homedir(),
|
|
146
152
|
".config",
|
|
147
153
|
"toolnet-memory",
|
|
148
154
|
"opencode-sync-status.json"
|
|
149
155
|
)
|
|
150
156
|
|
|
157
|
+
function projectStatusFile(
|
|
158
|
+
data
|
|
159
|
+
) {
|
|
160
|
+
if (
|
|
161
|
+
typeof data?.projectRoot ===
|
|
162
|
+
"string" &&
|
|
163
|
+
data.projectRoot.length > 0
|
|
164
|
+
) {
|
|
165
|
+
return path.join(
|
|
166
|
+
data.projectRoot,
|
|
167
|
+
".toolnet",
|
|
168
|
+
"runtime",
|
|
169
|
+
"opencode-status.json"
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return GLOBAL_STATUS_FILE
|
|
174
|
+
}
|
|
175
|
+
|
|
151
176
|
function writeStatus(data) {
|
|
152
177
|
try {
|
|
178
|
+
const statusFile =
|
|
179
|
+
projectStatusFile(
|
|
180
|
+
data
|
|
181
|
+
)
|
|
182
|
+
|
|
153
183
|
fs.mkdirSync(
|
|
154
184
|
path.dirname(
|
|
155
|
-
|
|
185
|
+
statusFile
|
|
156
186
|
),
|
|
157
187
|
{
|
|
158
188
|
recursive: true,
|
|
@@ -160,7 +190,7 @@ function writeStatus(data) {
|
|
|
160
190
|
)
|
|
161
191
|
|
|
162
192
|
fs.writeFileSync(
|
|
163
|
-
|
|
193
|
+
statusFile,
|
|
164
194
|
JSON.stringify(
|
|
165
195
|
{
|
|
166
196
|
timestamp:
|
|
@@ -287,7 +317,7 @@ async function runWithTimeout(
|
|
|
287
317
|
{
|
|
288
318
|
stdout = "ignore",
|
|
289
319
|
timeout =
|
|
290
|
-
|
|
320
|
+
REMOTE_TIMEOUT_MS,
|
|
291
321
|
} = {}
|
|
292
322
|
) {
|
|
293
323
|
const child =
|
|
@@ -389,14 +419,67 @@ export const ToolNetMemoryPlugin =
|
|
|
389
419
|
let lastSessionId =
|
|
390
420
|
null
|
|
391
421
|
|
|
392
|
-
|
|
422
|
+
/*
|
|
423
|
+
* Two independent lanes:
|
|
424
|
+
*
|
|
425
|
+
* captureChain:
|
|
426
|
+
* OpenCode DB -> local fsync WAL -> current work
|
|
427
|
+
*
|
|
428
|
+
* remoteInFlight:
|
|
429
|
+
* WAL -> Hugging Face / S3
|
|
430
|
+
*
|
|
431
|
+
* A slow remote backend must never block local capture.
|
|
432
|
+
*/
|
|
433
|
+
let captureChain =
|
|
393
434
|
Promise.resolve()
|
|
394
435
|
|
|
436
|
+
let remoteInFlight =
|
|
437
|
+
null
|
|
438
|
+
|
|
439
|
+
let debounceTimer =
|
|
440
|
+
null
|
|
441
|
+
|
|
395
442
|
let contextCache = {
|
|
396
443
|
value: "",
|
|
397
444
|
expiresAt: 0,
|
|
398
445
|
}
|
|
399
446
|
|
|
447
|
+
/*
|
|
448
|
+
* Compact startup context is injected once
|
|
449
|
+
* per native OpenCode session.
|
|
450
|
+
*
|
|
451
|
+
* Deep history is retrieved through
|
|
452
|
+
* memory_agent_ask / MCP on demand.
|
|
453
|
+
*/
|
|
454
|
+
const injectedSessions =
|
|
455
|
+
new Set()
|
|
456
|
+
|
|
457
|
+
function contextSessionKey(
|
|
458
|
+
input
|
|
459
|
+
) {
|
|
460
|
+
const candidates = [
|
|
461
|
+
input?.sessionID,
|
|
462
|
+
input?.sessionId,
|
|
463
|
+
input?.session?.id,
|
|
464
|
+
input?.info?.id,
|
|
465
|
+
lastSessionId,
|
|
466
|
+
]
|
|
467
|
+
|
|
468
|
+
const sessionId =
|
|
469
|
+
candidates.find(
|
|
470
|
+
value =>
|
|
471
|
+
typeof value ===
|
|
472
|
+
"string" &&
|
|
473
|
+
value.length > 0
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
return sessionId
|
|
477
|
+
? "session:" +
|
|
478
|
+
sessionId
|
|
479
|
+
: "project:" +
|
|
480
|
+
projectRoot
|
|
481
|
+
}
|
|
482
|
+
|
|
400
483
|
async function readContext() {
|
|
401
484
|
const now =
|
|
402
485
|
Date.now()
|
|
@@ -468,8 +551,13 @@ export const ToolNetMemoryPlugin =
|
|
|
468
551
|
|
|
469
552
|
async function syncNow(
|
|
470
553
|
sessionId,
|
|
471
|
-
|
|
472
|
-
|
|
554
|
+
{
|
|
555
|
+
flag = null,
|
|
556
|
+
reason = "unknown",
|
|
557
|
+
localOnly = false,
|
|
558
|
+
timeout =
|
|
559
|
+
REMOTE_TIMEOUT_MS,
|
|
560
|
+
} = {}
|
|
473
561
|
) {
|
|
474
562
|
if (!sessionId) {
|
|
475
563
|
return
|
|
@@ -489,9 +577,18 @@ export const ToolNetMemoryPlugin =
|
|
|
489
577
|
)
|
|
490
578
|
}
|
|
491
579
|
|
|
580
|
+
if (localOnly) {
|
|
581
|
+
args.push(
|
|
582
|
+
"--local-only"
|
|
583
|
+
)
|
|
584
|
+
}
|
|
585
|
+
|
|
492
586
|
try {
|
|
493
587
|
await runWithTimeout(
|
|
494
|
-
args
|
|
588
|
+
args,
|
|
589
|
+
{
|
|
590
|
+
timeout,
|
|
591
|
+
}
|
|
495
592
|
)
|
|
496
593
|
|
|
497
594
|
writeStatus({
|
|
@@ -499,8 +596,14 @@ export const ToolNetMemoryPlugin =
|
|
|
499
596
|
projectRoot,
|
|
500
597
|
sessionId,
|
|
501
598
|
reason,
|
|
599
|
+
mode:
|
|
600
|
+
localOnly
|
|
601
|
+
? "local"
|
|
602
|
+
: "remote",
|
|
502
603
|
state:
|
|
503
|
-
|
|
604
|
+
localOnly
|
|
605
|
+
? "capture-success"
|
|
606
|
+
: "sync-success",
|
|
504
607
|
})
|
|
505
608
|
} catch (error) {
|
|
506
609
|
writeStatus({
|
|
@@ -508,8 +611,14 @@ export const ToolNetMemoryPlugin =
|
|
|
508
611
|
projectRoot,
|
|
509
612
|
sessionId,
|
|
510
613
|
reason,
|
|
614
|
+
mode:
|
|
615
|
+
localOnly
|
|
616
|
+
? "local"
|
|
617
|
+
: "remote",
|
|
511
618
|
state:
|
|
512
|
-
|
|
619
|
+
localOnly
|
|
620
|
+
? "capture-failed"
|
|
621
|
+
: "sync-failed",
|
|
513
622
|
error:
|
|
514
623
|
error instanceof
|
|
515
624
|
Error
|
|
@@ -523,20 +632,24 @@ export const ToolNetMemoryPlugin =
|
|
|
523
632
|
}
|
|
524
633
|
}
|
|
525
634
|
|
|
526
|
-
function
|
|
635
|
+
function queueCapture(
|
|
527
636
|
sessionId,
|
|
528
637
|
flag,
|
|
529
638
|
reason
|
|
530
639
|
) {
|
|
531
640
|
if (!sessionId) {
|
|
532
|
-
return
|
|
641
|
+
return captureChain
|
|
533
642
|
}
|
|
534
643
|
|
|
535
644
|
lastSessionId =
|
|
536
645
|
sessionId
|
|
537
646
|
|
|
538
|
-
|
|
539
|
-
|
|
647
|
+
/*
|
|
648
|
+
* Local captures are serialized with each other,
|
|
649
|
+
* but completely independent from remote sync.
|
|
650
|
+
*/
|
|
651
|
+
captureChain =
|
|
652
|
+
captureChain
|
|
540
653
|
.catch(
|
|
541
654
|
() =>
|
|
542
655
|
undefined
|
|
@@ -545,46 +658,162 @@ export const ToolNetMemoryPlugin =
|
|
|
545
658
|
() =>
|
|
546
659
|
syncNow(
|
|
547
660
|
sessionId,
|
|
548
|
-
|
|
549
|
-
|
|
661
|
+
{
|
|
662
|
+
flag,
|
|
663
|
+
reason,
|
|
664
|
+
localOnly: true,
|
|
665
|
+
timeout:
|
|
666
|
+
CAPTURE_TIMEOUT_MS,
|
|
667
|
+
}
|
|
550
668
|
)
|
|
551
669
|
)
|
|
670
|
+
.catch(
|
|
671
|
+
() =>
|
|
672
|
+
undefined
|
|
673
|
+
)
|
|
674
|
+
|
|
675
|
+
return captureChain
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function queueRemote(
|
|
679
|
+
sessionId,
|
|
680
|
+
flag,
|
|
681
|
+
reason
|
|
682
|
+
) {
|
|
683
|
+
if (!sessionId) {
|
|
684
|
+
return Promise.resolve()
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
lastSessionId =
|
|
688
|
+
sessionId
|
|
689
|
+
|
|
690
|
+
/*
|
|
691
|
+
* Never build an endless remote backlog.
|
|
692
|
+
* One remote flush is enough because WAL keeps
|
|
693
|
+
* every pending local event until acknowledged.
|
|
694
|
+
*/
|
|
695
|
+
if (remoteInFlight) {
|
|
696
|
+
return remoteInFlight
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
remoteInFlight =
|
|
700
|
+
syncNow(
|
|
701
|
+
sessionId,
|
|
702
|
+
{
|
|
703
|
+
flag,
|
|
704
|
+
reason,
|
|
705
|
+
localOnly: false,
|
|
706
|
+
timeout:
|
|
707
|
+
REMOTE_TIMEOUT_MS,
|
|
708
|
+
}
|
|
709
|
+
)
|
|
710
|
+
.catch(
|
|
711
|
+
() =>
|
|
712
|
+
undefined
|
|
713
|
+
)
|
|
714
|
+
.finally(
|
|
715
|
+
() => {
|
|
716
|
+
remoteInFlight =
|
|
717
|
+
null
|
|
718
|
+
}
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
return remoteInFlight
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function scheduleCapture(
|
|
725
|
+
sessionId,
|
|
726
|
+
reason
|
|
727
|
+
) {
|
|
728
|
+
if (!sessionId) {
|
|
729
|
+
return
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (debounceTimer) {
|
|
733
|
+
clearTimeout(
|
|
734
|
+
debounceTimer
|
|
735
|
+
)
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
debounceTimer =
|
|
739
|
+
setTimeout(
|
|
740
|
+
() => {
|
|
741
|
+
debounceTimer =
|
|
742
|
+
null
|
|
743
|
+
|
|
744
|
+
void queueCapture(
|
|
745
|
+
sessionId,
|
|
746
|
+
null,
|
|
747
|
+
reason
|
|
748
|
+
)
|
|
749
|
+
},
|
|
750
|
+
EVENT_CAPTURE_DEBOUNCE_MS
|
|
751
|
+
)
|
|
552
752
|
|
|
553
|
-
|
|
753
|
+
if (
|
|
754
|
+
typeof debounceTimer.unref ===
|
|
755
|
+
"function"
|
|
756
|
+
) {
|
|
757
|
+
debounceTimer.unref()
|
|
758
|
+
}
|
|
554
759
|
}
|
|
555
760
|
|
|
556
761
|
/*
|
|
557
|
-
*
|
|
762
|
+
* Crash-safe LOCAL checkpoint.
|
|
558
763
|
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* abrupt SSH/process termination may
|
|
562
|
-
* skip shutdown hooks.
|
|
764
|
+
* Fast lane:
|
|
765
|
+
* OpenCode DB -> fsync WAL -> current work.
|
|
563
766
|
*
|
|
564
|
-
*
|
|
565
|
-
* from keeping OpenCode alive.
|
|
767
|
+
* No network dependency.
|
|
566
768
|
*/
|
|
567
|
-
const
|
|
769
|
+
const localPeriodic =
|
|
568
770
|
setInterval(
|
|
569
771
|
() => {
|
|
570
772
|
if (
|
|
571
773
|
lastSessionId
|
|
572
774
|
) {
|
|
573
|
-
void
|
|
775
|
+
void queueCapture(
|
|
574
776
|
lastSessionId,
|
|
575
777
|
null,
|
|
576
|
-
"periodic"
|
|
778
|
+
"periodic-local"
|
|
577
779
|
)
|
|
578
780
|
}
|
|
579
781
|
},
|
|
580
|
-
|
|
782
|
+
LOCAL_CAPTURE_MS
|
|
581
783
|
)
|
|
582
784
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
785
|
+
/*
|
|
786
|
+
* Remote durability is deliberately slower
|
|
787
|
+
* and independent from the local lane.
|
|
788
|
+
*/
|
|
789
|
+
const remotePeriodic =
|
|
790
|
+
setInterval(
|
|
791
|
+
() => {
|
|
792
|
+
if (
|
|
793
|
+
lastSessionId
|
|
794
|
+
) {
|
|
795
|
+
void queueRemote(
|
|
796
|
+
lastSessionId,
|
|
797
|
+
null,
|
|
798
|
+
"periodic-remote"
|
|
799
|
+
)
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
REMOTE_SYNC_MS
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
for (
|
|
806
|
+
const timer of [
|
|
807
|
+
localPeriodic,
|
|
808
|
+
remotePeriodic,
|
|
809
|
+
]
|
|
586
810
|
) {
|
|
587
|
-
|
|
811
|
+
if (
|
|
812
|
+
typeof timer.unref ===
|
|
813
|
+
"function"
|
|
814
|
+
) {
|
|
815
|
+
timer.unref()
|
|
816
|
+
}
|
|
588
817
|
}
|
|
589
818
|
|
|
590
819
|
return {
|
|
@@ -601,14 +830,39 @@ export const ToolNetMemoryPlugin =
|
|
|
601
830
|
sessionId
|
|
602
831
|
}
|
|
603
832
|
|
|
833
|
+
const terminalEvent =
|
|
834
|
+
event.type ===
|
|
835
|
+
"session.idle" ||
|
|
836
|
+
event.type ===
|
|
837
|
+
"session.compacted" ||
|
|
838
|
+
event.type ===
|
|
839
|
+
"session.error"
|
|
840
|
+
|
|
841
|
+
if (
|
|
842
|
+
sessionId &&
|
|
843
|
+
!terminalEvent
|
|
844
|
+
) {
|
|
845
|
+
scheduleCapture(
|
|
846
|
+
sessionId,
|
|
847
|
+
"event:" +
|
|
848
|
+
event.type
|
|
849
|
+
)
|
|
850
|
+
}
|
|
851
|
+
|
|
604
852
|
if (
|
|
605
853
|
event.type ===
|
|
606
854
|
"session.idle"
|
|
607
855
|
) {
|
|
608
|
-
await
|
|
856
|
+
await queueCapture(
|
|
609
857
|
sessionId,
|
|
610
858
|
"--idle",
|
|
611
|
-
"session.idle"
|
|
859
|
+
"session.idle:capture"
|
|
860
|
+
)
|
|
861
|
+
|
|
862
|
+
void queueRemote(
|
|
863
|
+
sessionId,
|
|
864
|
+
null,
|
|
865
|
+
"session.idle:remote"
|
|
612
866
|
)
|
|
613
867
|
|
|
614
868
|
return
|
|
@@ -618,10 +872,16 @@ export const ToolNetMemoryPlugin =
|
|
|
618
872
|
event.type ===
|
|
619
873
|
"session.compacted"
|
|
620
874
|
) {
|
|
621
|
-
await
|
|
875
|
+
await queueCapture(
|
|
622
876
|
sessionId,
|
|
623
877
|
"--compacted",
|
|
624
|
-
"session.compacted"
|
|
878
|
+
"session.compacted:capture"
|
|
879
|
+
)
|
|
880
|
+
|
|
881
|
+
void queueRemote(
|
|
882
|
+
sessionId,
|
|
883
|
+
null,
|
|
884
|
+
"session.compacted:remote"
|
|
625
885
|
)
|
|
626
886
|
|
|
627
887
|
contextCache = {
|
|
@@ -636,10 +896,16 @@ export const ToolNetMemoryPlugin =
|
|
|
636
896
|
event.type ===
|
|
637
897
|
"session.error"
|
|
638
898
|
) {
|
|
639
|
-
await
|
|
899
|
+
await queueCapture(
|
|
640
900
|
sessionId,
|
|
641
901
|
"--error",
|
|
642
|
-
"session.error"
|
|
902
|
+
"session.error:capture"
|
|
903
|
+
)
|
|
904
|
+
|
|
905
|
+
void queueRemote(
|
|
906
|
+
sessionId,
|
|
907
|
+
null,
|
|
908
|
+
"session.error:remote"
|
|
643
909
|
)
|
|
644
910
|
|
|
645
911
|
return
|
|
@@ -655,9 +921,26 @@ export const ToolNetMemoryPlugin =
|
|
|
655
921
|
*/
|
|
656
922
|
"experimental.chat.system.transform":
|
|
657
923
|
async (
|
|
658
|
-
|
|
924
|
+
input,
|
|
659
925
|
output
|
|
660
926
|
) => {
|
|
927
|
+
const injectionKey =
|
|
928
|
+
contextSessionKey(
|
|
929
|
+
input
|
|
930
|
+
)
|
|
931
|
+
|
|
932
|
+
/*
|
|
933
|
+
* Never inject ToolNet context on
|
|
934
|
+
* every model turn.
|
|
935
|
+
*/
|
|
936
|
+
if (
|
|
937
|
+
injectedSessions.has(
|
|
938
|
+
injectionKey
|
|
939
|
+
)
|
|
940
|
+
) {
|
|
941
|
+
return
|
|
942
|
+
}
|
|
943
|
+
|
|
661
944
|
const context =
|
|
662
945
|
await readContext()
|
|
663
946
|
|
|
@@ -674,6 +957,10 @@ export const ToolNetMemoryPlugin =
|
|
|
674
957
|
context
|
|
675
958
|
)
|
|
676
959
|
|
|
960
|
+
injectedSessions.add(
|
|
961
|
+
injectionKey
|
|
962
|
+
)
|
|
963
|
+
|
|
677
964
|
return
|
|
678
965
|
}
|
|
679
966
|
|
|
@@ -683,8 +970,14 @@ export const ToolNetMemoryPlugin =
|
|
|
683
970
|
) {
|
|
684
971
|
output.system =
|
|
685
972
|
output.system
|
|
686
|
-
?
|
|
973
|
+
? output.system +
|
|
974
|
+
"\\n\\n" +
|
|
975
|
+
context
|
|
687
976
|
: context
|
|
977
|
+
|
|
978
|
+
injectedSessions.add(
|
|
979
|
+
injectionKey
|
|
980
|
+
)
|
|
688
981
|
}
|
|
689
982
|
},
|
|
690
983
|
|
|
@@ -720,39 +1013,52 @@ export const ToolNetMemoryPlugin =
|
|
|
720
1013
|
*/
|
|
721
1014
|
dispose: async () => {
|
|
722
1015
|
clearInterval(
|
|
723
|
-
|
|
1016
|
+
localPeriodic
|
|
1017
|
+
)
|
|
1018
|
+
|
|
1019
|
+
clearInterval(
|
|
1020
|
+
remotePeriodic
|
|
724
1021
|
)
|
|
725
1022
|
|
|
1023
|
+
if (debounceTimer) {
|
|
1024
|
+
clearTimeout(
|
|
1025
|
+
debounceTimer
|
|
1026
|
+
)
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
/*
|
|
1030
|
+
* On a clean exit we only REQUIRE the
|
|
1031
|
+
* fast local fsync checkpoint.
|
|
1032
|
+
*
|
|
1033
|
+
* Never hold OpenCode shutdown hostage
|
|
1034
|
+
* to a slow remote backend.
|
|
1035
|
+
*/
|
|
726
1036
|
if (
|
|
727
1037
|
lastSessionId
|
|
728
1038
|
) {
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
)
|
|
735
|
-
} catch {
|
|
736
|
-
// Status already recorded.
|
|
737
|
-
}
|
|
1039
|
+
await queueCapture(
|
|
1040
|
+
lastSessionId,
|
|
1041
|
+
"--idle",
|
|
1042
|
+
"dispose:capture"
|
|
1043
|
+
)
|
|
738
1044
|
}
|
|
739
1045
|
|
|
740
1046
|
try {
|
|
741
|
-
await
|
|
1047
|
+
await captureChain
|
|
742
1048
|
} catch {
|
|
743
|
-
//
|
|
1049
|
+
// Fail open.
|
|
744
1050
|
}
|
|
745
1051
|
},
|
|
746
1052
|
}
|
|
747
1053
|
}
|
|
748
|
-
`;return se(t,i.trimStart(),{encoding:"utf8",mode:384}),t}import{existsSync as le,mkdirSync as ct,readFileSync as at,renameSync as lt,writeFileSync as ut}from"node:fs";import{dirname as ue,join as dt}from"node:path";function f(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function
|
|
749
|
-
`,{encoding:"utf8",mode:384}),lt(t,e)}function ce(e){if(!le(e))return{};let n=at(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid existing OpenCode opencode.json: ${o instanceof Error?o.message:String(o)}`)}if(!f(t))throw new Error("Invalid existing OpenCode opencode.json: root must be a JSON object.");return t}function ae(e,n){if(!f(e))return!1;let t=e.command;return e.type==="local"&&e.enabled!==!1&&Array.isArray(t)&&t.length===2&&t[0]===n&&t[1]==="mcp"}function
|
|
1054
|
+
`;return se(t,i.trimStart(),{encoding:"utf8",mode:384}),t}import{existsSync as le,mkdirSync as ct,readFileSync as at,renameSync as lt,writeFileSync as ut}from"node:fs";import{dirname as ue,join as dt}from"node:path";function f(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function mt(e,n){ct(ue(e),{recursive:!0});let t=`${e}.tmp-${process.pid}-${Date.now()}`;ut(t,`${JSON.stringify(n,null,2)}
|
|
1055
|
+
`,{encoding:"utf8",mode:384}),lt(t,e)}function ce(e){if(!le(e))return{};let n=at(e,"utf8").trim();if(!n)return{};let t;try{t=JSON.parse(n)}catch(o){throw new Error(`Invalid existing OpenCode opencode.json: ${o instanceof Error?o.message:String(o)}`)}if(!f(t))throw new Error("Invalid existing OpenCode opencode.json: root must be a JSON object.");return t}function ae(e,n){if(!f(e))return!1;let t=e.command;return e.type==="local"&&e.enabled!==!1&&Array.isArray(t)&&t.length===2&&t[0]===n&&t[1]==="mcp"}function gt(e,n){let t=e.mcpServers;if(!f(t)||!Object.prototype.hasOwnProperty.call(t,n))return{root:e,changed:!1};let o={...t};return delete o[n],{root:{...e,mcpServers:o},changed:!0}}function de(e={}){let n=e.configFile??$(),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",i=dt(ue(n),"opencode.jsonc"),s=le(i)?i:void 0,r=ce(n),c=gt(r,o),l=c.root,u=l.mcp;if(u!==void 0&&!f(u))throw new Error("Invalid existing OpenCode config: mcp must be an object.");let a=f(u)?{...u}:{},g=a[o];if(ae(g,t)&&!c.changed)return{installed:!0,changed:!1,configFile:n,serverName:o,command:[t,"mcp"],preservedJsonc:s};a[o]={type:"local",command:[t,"mcp"],enabled:!0};let d={...l,mcp:a};mt(n,d);let R=ce(n);if(!f(R.mcp)||!ae(R.mcp[o],t))throw new Error("OpenCode MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:n,serverName:o,command:[t,"mcp"],preservedJsonc:s}}import{existsSync as pt,mkdirSync as me,readFileSync as ft,writeFileSync as ge}from"node:fs";import{homedir as pe}from"node:os";import{dirname as fe,join as j}from"node:path";function yt(e){let n=[],t=/"((?:\\.|[^"\\])*)"|'([^']*)'/g,o;for(;o=t.exec(e);){let i=o[1]??o[2]??"";try{n.push(o[1]!==void 0?JSON.parse(`"${i}"`):i)}catch{n.push(i)}}return n}function ye(e={}){let n=e.configFile??j(process.env.CODEX_HOME??j(pe(),".codex"),"config.toml"),t=e.previousFile??j(pe(),".config","toolnet-memory","codex-notify-previous.json");me(fe(n),{recursive:!0}),me(fe(t),{recursive:!0});let o=pt(n)?ft(n,"utf8"):"",i=e.binary??"toolnet-memory",s=`notify = [${JSON.stringify(i)}, "session:codex-notify"]`,r=o.split(`
|
|
750
1056
|
`),c=r.findIndex(d=>/^\s*\[/.test(d));c<0&&(c=r.length);let l=-1,u=-1;for(let d=0;d<c;d+=1)if(/^\s*notify\s*=/.test(r[d])){if(l=d,u=d,r[d].includes("[")&&!r[d].includes("]"))for(;u+1<c&&(u+=1,!r[u].includes("]")););break}let a=[];if(l>=0){let d=r.slice(l,u+1).join(`
|
|
751
|
-
`);a=yt(d),r.splice(l,u-l+1,s)}else c=r.findIndex(d=>/^\s*\[/.test(d)),c<0&&(c=r.length),r.splice(c,0,s);let
|
|
1057
|
+
`);a=yt(d),r.splice(l,u-l+1,s)}else c=r.findIndex(d=>/^\s*\[/.test(d)),c<0&&(c=r.length),r.splice(c,0,s);let g=a.length>=2&&a[a.length-1]==="session:codex-notify";return a.length>0&&!g&&ge(t,JSON.stringify(a,null,2)+`
|
|
752
1058
|
`,{encoding:"utf8",mode:384}),o=r.join(`
|
|
753
1059
|
`),o.endsWith(`
|
|
754
1060
|
`)||(o+=`
|
|
755
|
-
`),
|
|
756
|
-
`,{encoding:"utf8",mode:384}),n}import{spawnSync as wt}from"node:child_process";function
|
|
757
|
-
`,{encoding:"utf8",mode:384}),
|
|
758
|
-
`,{encoding:"utf8",mode:384}),
|
|
1061
|
+
`),ge(n,o,{encoding:"utf8",mode:384}),{configFile:n,previousFile:t,preservedPrevious:a.length>0&&!g}}import{existsSync as ht,mkdirSync as Ot,readFileSync as vt,writeFileSync as xt}from"node:fs";import{homedir as Ct}from"node:os";import{dirname as St,join as he}from"node:path";function bt(e){return`'${e.replace(/'/g,"'\\''")}'`}function Oe(e={}){let n=e.hooksFile??he(process.env.CODEX_HOME??he(Ct(),".codex"),"hooks.json");Ot(St(n),{recursive:!0});let t={};if(ht(n))try{t=JSON.parse(vt(n,"utf8"))}catch(c){throw new Error(`Invalid existing Codex hooks.json: ${c instanceof Error?c.message:String(c)}`)}let o=t.hooks&&typeof t.hooks=="object"&&!Array.isArray(t.hooks)?t.hooks:{};t.hooks=o;let s=(Array.isArray(o.SessionStart)?o.SessionStart:[]).filter(c=>{try{return!JSON.stringify(c).includes("session:codex-context")}catch{return!0}}),r=e.binary??"toolnet-memory";return s.push({matcher:"startup|resume|clear|compact",hooks:[{type:"command",command:`${bt(r)} session:codex-context`,timeout:15,additionalContextLimit:1e3,statusMessage:"Loading ToolNet project continuity"}]}),o.SessionStart=s,xt(n,JSON.stringify(t,null,2)+`
|
|
1062
|
+
`,{encoding:"utf8",mode:384}),n}import{spawnSync as wt}from"node:child_process";function A(e,n){return wt(e,n,{encoding:"utf8",stdio:["ignore","pipe","pipe"]})}function ve(e,n){let t=A(e,["mcp","get",n,"--json"]);if(t.status!==0||!t.stdout)return null;try{return JSON.parse(t.stdout)}catch{return null}}function xe(e,n){return e.enabled!==!1&&e.transport?.type==="stdio"&&e.transport?.command===n&&Array.isArray(e.transport?.args)&&e.transport?.args.length===1&&e.transport.args[0]==="mcp"}function Ce(e={}){let n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=e.codexBinary??"codex",o=e.serverName??"toolnet-memory",i=ve(t,o);if(i&&xe(i,n))return{installed:!0,changed:!1,serverName:o,command:n,args:["mcp"]};if(i){let c=A(t,["mcp","remove",o]);if(c.status!==0)return{installed:!1,changed:!1,serverName:o,command:n,args:["mcp"],error:(c.stderr||c.stdout||"Unable to remove old ToolNet MCP configuration.").trim()}}let s=A(t,["mcp","add",o,"--",n,"mcp"]);if(s.status!==0)return{installed:!1,changed:!1,serverName:o,command:n,args:["mcp"],error:(s.stderr||s.stdout||"Unable to register ToolNet MCP.").trim()};let r=ve(t,o);return!r||!xe(r,n)?{installed:!1,changed:!0,serverName:o,command:n,args:["mcp"],error:"Codex accepted MCP registration but verification did not match expected ToolNet command."}:{installed:!0,changed:!0,serverName:o,command:n,args:["mcp"]}}import{existsSync as It,mkdirSync as kt,readFileSync as Nt,renameSync as Tt,rmSync as Et,writeFileSync as jt}from"node:fs";import{dirname as At}from"node:path";function O(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Mt(e){return/^[A-Za-z0-9_./:-]+$/u.test(e)?e:`'${e.replace(/'/gu,"'\\''")}'`}function Ft(e){if(!It(e))return{};let n;try{n=JSON.parse(Nt(e,"utf8"))}catch(t){throw new Error(`Invalid existing Claude settings.json: ${t instanceof Error?t.message:String(t)}`)}if(!O(n))throw new Error("Invalid existing Claude settings.json: root must be a JSON object.");return n}function M(e){if(e===void 0)return[];if(!Array.isArray(e))throw new Error("Invalid existing Claude settings.json: hook event must be an array.");let n=[];for(let t of e){if(!O(t)){n.push(t);continue}let o=t.hooks;if(!Array.isArray(o)){n.push(t);continue}let i=o.filter(s=>{if(!O(s))return!0;let r=s.command;return!(typeof r=="string"&&r.includes("session:claude-hook"))});i.length!==0&&n.push({...t,hooks:i})}return n}function F(e){return{type:"command",command:e,timeout:10}}function Rt(e,n){kt(At(e),{recursive:!0,mode:448});let t=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{jt(t,JSON.stringify(n,null,2)+`
|
|
1063
|
+
`,{encoding:"utf8",mode:384}),Tt(t,e)}finally{Et(t,{force:!0})}}function Se(e={}){let n=e.settingsFile??U(),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=Ft(n),i=o.hooks;if(i!==void 0&&!O(i))throw new Error("Invalid existing Claude settings.json: hooks must be an object.");let s=O(i)?{...i}:{},r=`${Mt(t)} session:claude-hook`,c=M(s.SessionStart);c.push({matcher:"startup|resume|clear|compact",hooks:[F(r)]}),s.SessionStart=c;let l=M(s.PostToolUse);l.push({matcher:"Edit|Write",hooks:[F(r)]}),s.PostToolUse=l;let u=M(s.Stop);u.push({hooks:[F(r)]}),s.Stop=u;let a={...o,hooks:s},g=JSON.stringify(o),d=JSON.stringify(a);return g===d?{settingsFile:n,changed:!1}:(Rt(n,a),{settingsFile:n,changed:!0})}import{existsSync as _t,mkdirSync as Pt,readFileSync as Jt,renameSync as Dt,rmSync as $t,writeFileSync as Lt}from"node:fs";import{dirname as Ht}from"node:path";function v(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function be(e){if(!_t(e))return{};let n;try{n=JSON.parse(Jt(e,"utf8"))}catch(t){throw new Error(`Invalid existing Claude Code config: ${t instanceof Error?t.message:String(t)}`)}if(!v(n))throw new Error("Invalid existing Claude Code config: root must be a JSON object.");return n}function we(e,n){if(!v(e))return!1;let t=e.args;return e.type==="stdio"&&e.command===n&&Array.isArray(t)&&t.length===1&&t[0]==="mcp"}function Bt(e,n){Pt(Ht(e),{recursive:!0});let t=`${e}.toolnet-${process.pid}-${Date.now()}.tmp`;try{Lt(t,JSON.stringify(n,null,2)+`
|
|
1064
|
+
`,{encoding:"utf8",mode:384}),Dt(t,e)}finally{$t(t,{force:!0})}}function Ie(e={}){let n=e.stateFile??Y(),t=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",o=e.serverName??"toolnet-memory",i=be(n),s=i.mcpServers;if(s!==void 0&&!v(s))throw new Error("Invalid existing Claude Code config: mcpServers must be an object.");let r=v(s)?{...s}:{},c=r[o];if(we(c,t))return{installed:!0,changed:!1,configFile:n,serverName:o,command:[t,"mcp"],repaired:!1};let l=c!==void 0;r[o]={type:"stdio",command:t,args:["mcp"]},Bt(n,{...i,mcpServers:r});let a=be(n).mcpServers;if(!v(a)||!we(a[o],t))throw new Error("Claude Code MCP configuration was written but verification failed.");return{installed:!0,changed:!0,configFile:n,serverName:o,command:[t,"mcp"],repaired:l}}function ke(e={}){let n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=Se({binary:n,settingsFile:e.settingsFile}),o=Ie({binary:n,stateFile:e.stateFile});return{hooks:t,mcp:o,files:[t.settingsFile,o.configFile]}}function Ne(){return q()}function Ut(e={}){let n=e.binary??process.env.TOOLNET_MEMORY_BIN??"toolnet-memory",t=[],o=Ne(),i=new Map(o.map(s=>[s.agent,s.detected]));if(!(e.force===!0||i.get("agy")===!0))t.push({agent:"agy",detected:!1,installed:!1,targets:[]});else try{let r=te({binary:n});t.push({agent:"agy",detected:!0,installed:!0,targets:r.files})}catch(r){t.push({agent:"agy",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||i.get("opencode")===!0))t.push({agent:"opencode",detected:!1,installed:!1,targets:[]});else try{let r=ie({binary:n}),c=de({binary:n});t.push({agent:"opencode",detected:!0,installed:!0,targets:[r,c.configFile,`mcp:${c.serverName}`]})}catch(r){t.push({agent:"opencode",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||i.get("claude")===!0))t.push({agent:"claude",detected:!1,installed:!1,targets:[]});else try{let r=ke({binary:n});t.push({agent:"claude",detected:!0,installed:!0,targets:[r.hooks.settingsFile,r.mcp.configFile,`mcp:${r.mcp.serverName}`]})}catch(r){t.push({agent:"claude",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}if(!(e.force===!0||i.get("codex")===!0))t.push({agent:"codex",detected:!1,installed:!1,targets:[]});else try{let r=ye({binary:n}),c=Oe({binary:n}),l=Ce({binary:n});if(!l.installed)throw new Error(l.error??"Codex MCP registration failed");let u=[r.configFile,c,`mcp:${l.serverName}`];r.preservedPrevious&&u.push(r.previousFile),t.push({agent:"codex",detected:!0,installed:!0,targets:u})}catch(r){t.push({agent:"codex",detected:!0,installed:!1,targets:[],error:r instanceof Error?r.message:String(r)})}return t}function Yt(e){console.log(""),console.log("ToolNet Memory Integration Detection"),console.log("===================================="),console.log("");for(let n of e){let t=n.agent==="agy"?"Agy / Antigravity":n.agent==="opencode"?"OpenCode":n.agent==="claude"?"Claude Code":"Codex";if(!n.detected){console.log(`\u25CB ${t}: not detected`);continue}console.log(`\u2713 ${t}: detected`);for(let o of n.evidence)console.log(` ${o}`)}console.log("")}function qt(e){console.log(""),console.log("ToolNet Memory AI Integrations"),console.log("=============================="),console.log("");for(let n of e){let t=n.agent==="agy"?"Agy / Antigravity":n.agent==="opencode"?"OpenCode":"Codex";if(!n.detected){console.log(`- ${t}: not detected`);continue}if(n.installed){console.log(`\u2713 ${t}: automatic memory enabled`);continue}console.log(`\u2717 ${t}: integration failed`),n.error&&console.log(` ${n.error}`)}console.log("")}async function Wt(){let e=process.argv.slice(2),n=e.includes("--all"),t=e.includes("--json");if(e.includes("--detect-only")){let s=Ne();if(t){console.log(JSON.stringify(s,null,2));return}Yt(s);return}let i=Ut({force:n});if(t){console.log(JSON.stringify(i,null,2));return}qt(i)}var Gt=process.argv[1]&&(process.argv[1].endsWith("auto-integrate.js")||process.argv[1].endsWith("auto-integrate.ts"));Gt&&Wt().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});export{Ne as detectAutoIntegrations,Ut as installAutoIntegrations};
|