myagentmemory 0.4.13 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -24
- package/dist/cli-spec.d.ts +25 -0
- package/dist/cli-spec.js +211 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +375 -4
- package/dist/completions.d.ts +13 -0
- package/dist/completions.js +429 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +17 -12
- package/dist/hooks.d.ts +42 -0
- package/dist/hooks.js +444 -0
- package/dist/plugin-bootstrap.d.ts +190 -0
- package/dist/plugin-bootstrap.js +628 -0
- package/dist/plugin-host.d.ts +136 -0
- package/dist/plugin-host.js +98 -0
- package/dist/plugin-runtime.d.ts +21 -0
- package/dist/plugin-runtime.js +208 -0
- package/dist/plugin-service.d.ts +45 -0
- package/dist/plugin-service.js +395 -0
- package/docs/official-plugin-bootstrap.md +335 -0
- package/package.json +35 -2
- package/src/cli-spec.ts +236 -0
- package/src/cli.ts +391 -4
- package/src/completions.ts +501 -0
- package/src/core.ts +17 -12
- package/src/hooks.ts +485 -0
- package/src/plugin-bootstrap.ts +931 -0
- package/src/plugin-host.ts +255 -0
- package/src/plugin-runtime.ts +296 -0
- package/src/plugin-service.ts +451 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { COMMAND_DESCRIPTIONS, COMMAND_OPTIONS, COMMANDS, GLOBAL_OPTIONS, OPTION_SPECS, optionDescription, PLUGIN_COMMAND_DESCRIPTIONS, PLUGIN_COMMAND_OPTIONS, PLUGIN_COMMANDS, SCRATCHPAD_ACTION_DESCRIPTIONS, SCRATCHPAD_ACTION_OPTIONS, SCRATCHPAD_ACTIONS, SHELL_DESCRIPTIONS, WORKER_ACTION_DESCRIPTIONS, WORKER_ACTION_OPTIONS, WORKER_ACTIONS, } from "./cli-spec.js";
|
|
5
|
+
function words(values) {
|
|
6
|
+
return values.join(" ");
|
|
7
|
+
}
|
|
8
|
+
function zshOptionValue(command, option) {
|
|
9
|
+
if (option === "--target") {
|
|
10
|
+
return command === "read"
|
|
11
|
+
? ":target:(daily long_term scratchpad list topic topics)"
|
|
12
|
+
: ":target:(daily long_term topic)";
|
|
13
|
+
}
|
|
14
|
+
if (option === "--mode")
|
|
15
|
+
return command === "search" ? ":mode:(keyword semantic deep)" : ":mode:(append overwrite)";
|
|
16
|
+
if (option === "--scope")
|
|
17
|
+
return ":scope:(global current)";
|
|
18
|
+
if (option === "--host")
|
|
19
|
+
return command === "web" ? ":host:(127.0.0.1 localhost ::1)" : ":host:(pi codex claude)";
|
|
20
|
+
if (option === "--only")
|
|
21
|
+
return ":agent:(claude codex cursor opencode pi)";
|
|
22
|
+
const value = OPTION_SPECS[option]?.value;
|
|
23
|
+
if (value?.kind === "directory")
|
|
24
|
+
return `:${value.label}:_directories`;
|
|
25
|
+
if (value?.kind === "file")
|
|
26
|
+
return `:${value.label}:_files`;
|
|
27
|
+
if (value)
|
|
28
|
+
return `:${value.label}:`;
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
function zshOptionSpecs(command, options = COMMAND_OPTIONS[command] ?? []) {
|
|
32
|
+
return options
|
|
33
|
+
.map((option) => `'${option}[${optionDescription(option)}]${zshOptionValue(command, option)}'`)
|
|
34
|
+
.join(" ");
|
|
35
|
+
}
|
|
36
|
+
function fishOption(command, condition, option) {
|
|
37
|
+
const spec = OPTION_SPECS[option];
|
|
38
|
+
const value = spec?.value ? " -r" : "";
|
|
39
|
+
let suggestions = "";
|
|
40
|
+
if (option === "--target")
|
|
41
|
+
suggestions =
|
|
42
|
+
command === "read" ? " -a 'daily long_term scratchpad list topic topics'" : " -a 'daily long_term topic'";
|
|
43
|
+
else if (option === "--mode")
|
|
44
|
+
suggestions = command === "search" ? " -a 'keyword semantic deep'" : " -a 'append overwrite'";
|
|
45
|
+
else if (option === "--scope")
|
|
46
|
+
suggestions = " -a 'global current'";
|
|
47
|
+
else if (option === "--host")
|
|
48
|
+
suggestions = command === "web" ? " -a '127.0.0.1 localhost ::1'" : " -a 'pi codex claude'";
|
|
49
|
+
else if (option === "--only")
|
|
50
|
+
suggestions = " -a 'claude codex cursor opencode pi'";
|
|
51
|
+
else if (spec?.value?.kind === "directory")
|
|
52
|
+
suggestions = " -a '(__fish_complete_directories)'";
|
|
53
|
+
else if (spec?.value?.kind === "file")
|
|
54
|
+
suggestions = " -F";
|
|
55
|
+
return `complete -c agent-memory -n '${condition}' -l ${option.slice(2)}${value}${suggestions} -d '${optionDescription(option)}'`;
|
|
56
|
+
}
|
|
57
|
+
function bashCompletion() {
|
|
58
|
+
return `# agent-memory completion for Bash
|
|
59
|
+
# Installed automatically by: agent-memory completion bash
|
|
60
|
+
# Print this script instead with: agent-memory completion bash --stdout
|
|
61
|
+
_agent_memory_completion() {
|
|
62
|
+
local cur command sub action
|
|
63
|
+
COMPREPLY=()
|
|
64
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
65
|
+
command="\${COMP_WORDS[1]}"
|
|
66
|
+
sub="\${COMP_WORDS[2]}"
|
|
67
|
+
action="\${COMP_WORDS[3]}"
|
|
68
|
+
|
|
69
|
+
if [[ "$cur" == --*=* ]]; then return 0; fi
|
|
70
|
+
case "\${COMP_WORDS[COMP_CWORD-1]}" in
|
|
71
|
+
--target)
|
|
72
|
+
if [[ "$command" == read ]]; then COMPREPLY=( $(compgen -W "daily long_term scratchpad list topic topics" -- "$cur") );
|
|
73
|
+
else COMPREPLY=( $(compgen -W "daily long_term topic" -- "$cur") ); fi; return 0 ;;
|
|
74
|
+
--mode)
|
|
75
|
+
if [[ "$command" == search ]]; then COMPREPLY=( $(compgen -W "keyword semantic deep" -- "$cur") );
|
|
76
|
+
else COMPREPLY=( $(compgen -W "append overwrite" -- "$cur") ); fi; return 0 ;;
|
|
77
|
+
--scope) COMPREPLY=( $(compgen -W "global current" -- "$cur") ); return 0 ;;
|
|
78
|
+
--host)
|
|
79
|
+
if [[ "$command" == web ]]; then COMPREPLY=( $(compgen -W "127.0.0.1 localhost ::1" -- "$cur") );
|
|
80
|
+
else COMPREPLY=( $(compgen -W "pi codex claude" -- "$cur") ); fi; return 0 ;;
|
|
81
|
+
--only) COMPREPLY=( $(compgen -W "claude codex cursor opencode pi" -- "$cur") ); return 0 ;;
|
|
82
|
+
--dir|--cwd|--pi|--codex|--claude|--state|--journal|--candidates-dir|--decisions-dir|--auto-dir|--output)
|
|
83
|
+
COMPREPLY=( $(compgen -f -- "$cur") ); return 0 ;;
|
|
84
|
+
esac
|
|
85
|
+
|
|
86
|
+
if (( COMP_CWORD == 1 )); then
|
|
87
|
+
COMPREPLY=( $(compgen -W "${words(COMMANDS)}" -- "$cur") ); return 0
|
|
88
|
+
fi
|
|
89
|
+
if [[ "$command" == plugin && $COMP_CWORD -eq 2 ]]; then
|
|
90
|
+
COMPREPLY=( $(compgen -W "${words(PLUGIN_COMMANDS)}" -- "$cur") ); return 0
|
|
91
|
+
fi
|
|
92
|
+
if [[ "$command" == plugin && "$sub" == worker && $COMP_CWORD -eq 3 ]]; then
|
|
93
|
+
COMPREPLY=( $(compgen -W "${words(WORKER_ACTIONS)}" -- "$cur") ); return 0
|
|
94
|
+
fi
|
|
95
|
+
if [[ "$command" == scratchpad && $COMP_CWORD -eq 2 ]]; then
|
|
96
|
+
COMPREPLY=( $(compgen -W "${words(SCRATCHPAD_ACTIONS)}" -- "$cur") ); return 0
|
|
97
|
+
fi
|
|
98
|
+
if [[ "$command" == completion && $COMP_CWORD -eq 2 ]]; then
|
|
99
|
+
COMPREPLY=( $(compgen -W "bash zsh fish powershell" -- "$cur") ); return 0
|
|
100
|
+
fi
|
|
101
|
+
local command_options=""
|
|
102
|
+
if [[ "$command" == plugin ]]; then
|
|
103
|
+
case "$sub" in
|
|
104
|
+
${Object.entries(PLUGIN_COMMAND_OPTIONS)
|
|
105
|
+
.map(([command, options]) => ` ${command}) command_options="${words(options)}" ;;`)
|
|
106
|
+
.join("\n")}
|
|
107
|
+
esac
|
|
108
|
+
if [[ "$sub" == worker && -n "$action" ]]; then
|
|
109
|
+
case "$action" in
|
|
110
|
+
${Object.entries(WORKER_ACTION_OPTIONS)
|
|
111
|
+
.map(([action, options]) => ` ${action}) command_options="${words(options)}" ;;`)
|
|
112
|
+
.join("\n")}
|
|
113
|
+
esac
|
|
114
|
+
fi
|
|
115
|
+
elif [[ "$command" == scratchpad && -n "$sub" ]]; then
|
|
116
|
+
case "$sub" in
|
|
117
|
+
${Object.entries(SCRATCHPAD_ACTION_OPTIONS)
|
|
118
|
+
.map(([action, options]) => ` ${action}) command_options="${words(options)}" ;;`)
|
|
119
|
+
.join("\n")}
|
|
120
|
+
esac
|
|
121
|
+
else
|
|
122
|
+
case "$command" in
|
|
123
|
+
${Object.entries(COMMAND_OPTIONS)
|
|
124
|
+
.map(([command, options]) => ` ${command}) command_options="${words(options)}" ;;`)
|
|
125
|
+
.join("\n")}
|
|
126
|
+
esac
|
|
127
|
+
fi
|
|
128
|
+
COMPREPLY=( $(compgen -W "${words(GLOBAL_OPTIONS)} $command_options" -- "$cur") )
|
|
129
|
+
}
|
|
130
|
+
complete -F _agent_memory_completion agent-memory
|
|
131
|
+
`;
|
|
132
|
+
}
|
|
133
|
+
function zshCompletion() {
|
|
134
|
+
return `#compdef agent-memory
|
|
135
|
+
# agent-memory completion for Zsh
|
|
136
|
+
# Installed automatically by: agent-memory completion zsh
|
|
137
|
+
# Print this script instead with: agent-memory completion zsh --stdout
|
|
138
|
+
_agent-memory() {
|
|
139
|
+
local -a commands plugin_commands worker_actions scratchpad_actions shells
|
|
140
|
+
local command="$words[2]"
|
|
141
|
+
local subcommand="$words[3]"
|
|
142
|
+
local action="$words[4]"
|
|
143
|
+
local command_position=$CURRENT
|
|
144
|
+
commands=(${COMMANDS.map((command) => `'${command}:${COMMAND_DESCRIPTIONS[command] ?? command}'`).join(" ")})
|
|
145
|
+
plugin_commands=(${PLUGIN_COMMANDS.map((command) => `'${command}:${PLUGIN_COMMAND_DESCRIPTIONS[command]}'`).join(" ")})
|
|
146
|
+
worker_actions=(${WORKER_ACTIONS.map((action) => `'${action}:${WORKER_ACTION_DESCRIPTIONS[action]}'`).join(" ")})
|
|
147
|
+
scratchpad_actions=(${SCRATCHPAD_ACTIONS.map((action) => `'${action}:${SCRATCHPAD_ACTION_DESCRIPTIONS[action]}'`).join(" ")})
|
|
148
|
+
shells=(${Object.entries(SHELL_DESCRIPTIONS)
|
|
149
|
+
.map(([shell, description]) => `'${shell}:${description}'`)
|
|
150
|
+
.join(" ")})
|
|
151
|
+
|
|
152
|
+
_arguments -C \\
|
|
153
|
+
'(-h --help)'{-h,--help}'[show help]' \\
|
|
154
|
+
'(-V --version)'{-V,--version}'[show version]' \\
|
|
155
|
+
'--json[emit structured JSON]' \\
|
|
156
|
+
'--dir[memory directory]:directory:_directories' \\
|
|
157
|
+
'1:command:->command' \\
|
|
158
|
+
'*::argument:->args'
|
|
159
|
+
|
|
160
|
+
case $state in
|
|
161
|
+
command) _describe 'command' commands ;;
|
|
162
|
+
args)
|
|
163
|
+
case $command in
|
|
164
|
+
plugin)
|
|
165
|
+
if (( command_position == 3 )); then _describe 'plugin command' plugin_commands
|
|
166
|
+
elif [[ "$subcommand" == worker ]] && (( command_position == 4 )); then _describe 'worker action' worker_actions
|
|
167
|
+
else
|
|
168
|
+
if [[ "$subcommand" == worker && -n "$action" ]]; then
|
|
169
|
+
case "$action" in
|
|
170
|
+
${Object.entries(WORKER_ACTION_OPTIONS)
|
|
171
|
+
.map(([action, options]) => ` ${action}) _arguments ${zshOptionSpecs(`plugin:worker:${action}`, options)} ;;`)
|
|
172
|
+
.join("\n")}
|
|
173
|
+
esac
|
|
174
|
+
else
|
|
175
|
+
case "$subcommand" in
|
|
176
|
+
${Object.entries(PLUGIN_COMMAND_OPTIONS)
|
|
177
|
+
.map(([command, options]) => ` ${command}) _arguments ${zshOptionSpecs(`plugin:${command}`, options)} ;;`)
|
|
178
|
+
.join("\n")}
|
|
179
|
+
esac
|
|
180
|
+
fi
|
|
181
|
+
fi ;;
|
|
182
|
+
scratchpad)
|
|
183
|
+
if (( command_position == 3 )); then _describe 'action' scratchpad_actions
|
|
184
|
+
else
|
|
185
|
+
case "$subcommand" in
|
|
186
|
+
${Object.entries(SCRATCHPAD_ACTION_OPTIONS)
|
|
187
|
+
.map(([action, options]) => ` ${action}) _arguments ${zshOptionSpecs("scratchpad", options)} ;;`)
|
|
188
|
+
.join("\n")}
|
|
189
|
+
esac
|
|
190
|
+
fi ;;
|
|
191
|
+
completion)
|
|
192
|
+
if (( command_position == 3 )); then _describe 'shell' shells
|
|
193
|
+
else _arguments ${zshOptionSpecs("completion")}; fi ;;
|
|
194
|
+
${Object.keys(COMMAND_OPTIONS)
|
|
195
|
+
.filter((command) => command !== "plugin" && command !== "scratchpad" && command !== "completion")
|
|
196
|
+
.map((command) => ` ${command}) _arguments ${zshOptionSpecs(command)} ;;`)
|
|
197
|
+
.join("\n")}
|
|
198
|
+
*) _arguments ;;
|
|
199
|
+
esac ;;
|
|
200
|
+
esac
|
|
201
|
+
}
|
|
202
|
+
compdef _agent-memory agent-memory
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
function fishCompletion() {
|
|
206
|
+
const lines = [
|
|
207
|
+
"# agent-memory completion for Fish",
|
|
208
|
+
"# Installed automatically by: agent-memory completion fish",
|
|
209
|
+
"# Print this script instead with: agent-memory completion fish --stdout",
|
|
210
|
+
"complete -c agent-memory -f",
|
|
211
|
+
...COMMANDS.map((command) => `complete -c agent-memory -n '__fish_use_subcommand' -a '${command}' -d '${COMMAND_DESCRIPTIONS[command] ?? command}'`),
|
|
212
|
+
...PLUGIN_COMMANDS.map((command) => `complete -c agent-memory -n '__fish_seen_subcommand_from plugin; and not __fish_seen_subcommand_from ${words(PLUGIN_COMMANDS)}' -a '${command}' -d '${PLUGIN_COMMAND_DESCRIPTIONS[command]}'`),
|
|
213
|
+
...WORKER_ACTIONS.map((action) => `complete -c agent-memory -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from worker; and not __fish_seen_subcommand_from ${words(WORKER_ACTIONS)}' -a '${action}' -d '${WORKER_ACTION_DESCRIPTIONS[action]}'`),
|
|
214
|
+
...SCRATCHPAD_ACTIONS.map((action) => `complete -c agent-memory -n '__fish_seen_subcommand_from scratchpad; and not __fish_seen_subcommand_from ${words(SCRATCHPAD_ACTIONS)}' -a '${action}' -d '${SCRATCHPAD_ACTION_DESCRIPTIONS[action]}'`),
|
|
215
|
+
...Object.entries(SHELL_DESCRIPTIONS).map(([shell, description]) => `complete -c agent-memory -n '__fish_seen_subcommand_from completion' -a '${shell}' -d '${description}'`),
|
|
216
|
+
"complete -c agent-memory -l dir -r -a '(__fish_complete_directories)' -d 'override the active memory directory'",
|
|
217
|
+
"complete -c agent-memory -l json -d 'emit command-specific structured JSON'",
|
|
218
|
+
"complete -c agent-memory -s h -l help -d 'show help for the selected command'",
|
|
219
|
+
"complete -c agent-memory -s V -l version -d 'print the installed version and exit'",
|
|
220
|
+
];
|
|
221
|
+
for (const [command, options] of Object.entries(COMMAND_OPTIONS)) {
|
|
222
|
+
if (command === "scratchpad")
|
|
223
|
+
continue;
|
|
224
|
+
for (const option of options) {
|
|
225
|
+
lines.push(fishOption(command, `__fish_seen_subcommand_from ${command}`, option));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (const [subcommand, options] of Object.entries(PLUGIN_COMMAND_OPTIONS)) {
|
|
229
|
+
if (subcommand === "worker")
|
|
230
|
+
continue;
|
|
231
|
+
for (const option of options) {
|
|
232
|
+
lines.push(fishOption(`plugin:${subcommand}`, `__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from ${subcommand}`, option));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
for (const [action, options] of Object.entries(WORKER_ACTION_OPTIONS)) {
|
|
236
|
+
for (const option of options) {
|
|
237
|
+
lines.push(fishOption(`plugin:worker:${action}`, `__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from worker; and __fish_seen_subcommand_from ${action}`, option));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
for (const [action, options] of Object.entries(SCRATCHPAD_ACTION_OPTIONS)) {
|
|
241
|
+
for (const option of options) {
|
|
242
|
+
lines.push(fishOption("scratchpad", `__fish_seen_subcommand_from scratchpad; and __fish_seen_subcommand_from ${action}`, option));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return `${lines.join("\n")}\n`;
|
|
246
|
+
}
|
|
247
|
+
function powershellCompletion() {
|
|
248
|
+
const psOptions = (options) => (options.length ? `@('${options.join("','")}')` : "@()");
|
|
249
|
+
const optionCases = Object.entries(COMMAND_OPTIONS)
|
|
250
|
+
.map(([command, options]) => ` '${command}' { $candidates += ${psOptions(options)} }`)
|
|
251
|
+
.join("\n");
|
|
252
|
+
const pluginOptionCases = Object.entries(PLUGIN_COMMAND_OPTIONS)
|
|
253
|
+
.map(([command, options]) => ` '${command}' { $candidates += ${psOptions(options)} }`)
|
|
254
|
+
.join("\n");
|
|
255
|
+
const workerOptionCases = Object.entries(WORKER_ACTION_OPTIONS)
|
|
256
|
+
.map(([action, options]) => ` '${action}' { $candidates += ${psOptions(options)} }`)
|
|
257
|
+
.join("\n");
|
|
258
|
+
const scratchpadOptionCases = Object.entries(SCRATCHPAD_ACTION_OPTIONS)
|
|
259
|
+
.map(([action, options]) => ` '${action}' { $candidates += ${psOptions(options)} }`)
|
|
260
|
+
.join("\n");
|
|
261
|
+
return `# agent-memory completion for PowerShell
|
|
262
|
+
# Installed automatically by: agent-memory completion powershell
|
|
263
|
+
# Print this script instead with: agent-memory completion powershell --stdout
|
|
264
|
+
Register-ArgumentCompleter -Native -CommandName agent-memory -ScriptBlock {
|
|
265
|
+
param($wordToComplete, $commandAst, $cursorPosition)
|
|
266
|
+
$tokens = @($commandAst.CommandElements | ForEach-Object { $_.ToString() })
|
|
267
|
+
$commands = @('${COMMANDS.join("','")}')
|
|
268
|
+
$pluginCommands = @('${PLUGIN_COMMANDS.join("','")}')
|
|
269
|
+
$workerActions = @('${WORKER_ACTIONS.join("','")}')
|
|
270
|
+
$scratchpadActions = @('${SCRATCHPAD_ACTIONS.join("','")}')
|
|
271
|
+
$shells = @('bash','zsh','fish','powershell')
|
|
272
|
+
$commandDescriptions = @{
|
|
273
|
+
${Object.entries(COMMAND_DESCRIPTIONS)
|
|
274
|
+
.map(([command, description]) => ` '${command}' = '${description}'`)
|
|
275
|
+
.join("\n")}
|
|
276
|
+
}
|
|
277
|
+
$pluginCommandDescriptions = @{
|
|
278
|
+
${Object.entries(PLUGIN_COMMAND_DESCRIPTIONS)
|
|
279
|
+
.map(([command, description]) => ` '${command}' = '${description}'`)
|
|
280
|
+
.join("\n")}
|
|
281
|
+
}
|
|
282
|
+
$workerActionDescriptions = @{
|
|
283
|
+
${Object.entries(WORKER_ACTION_DESCRIPTIONS)
|
|
284
|
+
.map(([action, description]) => ` '${action}' = '${description}'`)
|
|
285
|
+
.join("\n")}
|
|
286
|
+
}
|
|
287
|
+
$scratchpadActionDescriptions = @{
|
|
288
|
+
${Object.entries(SCRATCHPAD_ACTION_DESCRIPTIONS)
|
|
289
|
+
.map(([action, description]) => ` '${action}' = '${description}'`)
|
|
290
|
+
.join("\n")}
|
|
291
|
+
}
|
|
292
|
+
$shellDescriptions = @{
|
|
293
|
+
${Object.entries(SHELL_DESCRIPTIONS)
|
|
294
|
+
.map(([shell, description]) => ` '${shell}' = '${description}'`)
|
|
295
|
+
.join("\n")}
|
|
296
|
+
}
|
|
297
|
+
$optionDescriptions = @{
|
|
298
|
+
${Object.keys(OPTION_SPECS)
|
|
299
|
+
.map((option) => ` '${option}' = '${optionDescription(option)}'`)
|
|
300
|
+
.join("\n")}
|
|
301
|
+
}
|
|
302
|
+
$globalOptions = @('${GLOBAL_OPTIONS.join("','")}')
|
|
303
|
+
$command = if ($tokens.Count -gt 1) { $tokens[1] } else { '' }
|
|
304
|
+
$subcommand = if ($tokens.Count -gt 2) { $tokens[2] } else { '' }
|
|
305
|
+
$action = if ($tokens.Count -gt 3) { $tokens[3] } else { '' }
|
|
306
|
+
$candidates = @()
|
|
307
|
+
$candidateDescriptions = @{}
|
|
308
|
+
|
|
309
|
+
if ($tokens.Count -le 2) { $candidates = $commands + $globalOptions; $candidateDescriptions = $commandDescriptions }
|
|
310
|
+
elseif ($command -eq 'plugin' -and $tokens.Count -le 4 -and $tokens[2] -eq 'worker') { $candidates = $workerActions + $globalOptions; $candidateDescriptions = $workerActionDescriptions }
|
|
311
|
+
elseif ($command -eq 'plugin' -and $tokens.Count -le 3) { $candidates = $pluginCommands + $globalOptions; $candidateDescriptions = $pluginCommandDescriptions }
|
|
312
|
+
elseif ($command -eq 'scratchpad' -and $tokens.Count -le 3) { $candidates = $scratchpadActions + $globalOptions; $candidateDescriptions = $scratchpadActionDescriptions }
|
|
313
|
+
elseif ($command -eq 'completion' -and $tokens.Count -le 3) { $candidates = $shells; $candidateDescriptions = $shellDescriptions }
|
|
314
|
+
else {
|
|
315
|
+
$candidates = $globalOptions
|
|
316
|
+
$candidateDescriptions = $optionDescriptions
|
|
317
|
+
if ($command -eq 'plugin') {
|
|
318
|
+
if ($subcommand -eq 'worker' -and $action) {
|
|
319
|
+
switch ($action) {
|
|
320
|
+
${workerOptionCases}
|
|
321
|
+
}
|
|
322
|
+
} else {
|
|
323
|
+
switch ($subcommand) {
|
|
324
|
+
${pluginOptionCases}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
} elseif ($command -eq 'scratchpad') {
|
|
328
|
+
switch ($subcommand) {
|
|
329
|
+
${scratchpadOptionCases}
|
|
330
|
+
}
|
|
331
|
+
} else {
|
|
332
|
+
switch ($command) {
|
|
333
|
+
${optionCases}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
$candidates | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
339
|
+
$description = if ($candidateDescriptions.ContainsKey($_)) { $candidateDescriptions[$_] } elseif ($optionDescriptions.ContainsKey($_)) { $optionDescriptions[$_] } else { $_ }
|
|
340
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $description)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
export function generateCompletion(shell) {
|
|
346
|
+
switch (shell) {
|
|
347
|
+
case "bash":
|
|
348
|
+
return bashCompletion();
|
|
349
|
+
case "zsh":
|
|
350
|
+
return zshCompletion();
|
|
351
|
+
case "fish":
|
|
352
|
+
return fishCompletion();
|
|
353
|
+
case "powershell":
|
|
354
|
+
return powershellCompletion();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
export function detectCompletionShell(environment = process.env, platform = process.platform) {
|
|
358
|
+
const shell = path.basename(environment.SHELL ?? "").toLowerCase();
|
|
359
|
+
if (shell === "bash" || shell === "zsh" || shell === "fish")
|
|
360
|
+
return shell;
|
|
361
|
+
if (shell.includes("pwsh") || shell.includes("powershell"))
|
|
362
|
+
return "powershell";
|
|
363
|
+
if (platform === "win32" && environment.PSModulePath)
|
|
364
|
+
return "powershell";
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
function writeCompletionFile(filePath, content) {
|
|
368
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o755 });
|
|
369
|
+
fs.writeFileSync(filePath, content, { mode: 0o644 });
|
|
370
|
+
}
|
|
371
|
+
function ensureProfileBlock(filePath, lines) {
|
|
372
|
+
const start = "# >>> agent-memory completion >>>";
|
|
373
|
+
const end = "# <<< agent-memory completion <<<";
|
|
374
|
+
const block = `${start}\n${lines.join("\n")}\n${end}`;
|
|
375
|
+
const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf8") : "";
|
|
376
|
+
const startIndex = current.indexOf(start);
|
|
377
|
+
const endIndex = startIndex === -1 ? -1 : current.indexOf(end, startIndex);
|
|
378
|
+
let updated;
|
|
379
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
380
|
+
updated = `${current.slice(0, startIndex)}${block}${current.slice(endIndex + end.length)}`;
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
const separator = current.length === 0 || current.endsWith("\n") ? "" : "\n";
|
|
384
|
+
updated = `${current}${separator}${block}\n`;
|
|
385
|
+
}
|
|
386
|
+
if (updated === current)
|
|
387
|
+
return false;
|
|
388
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o755 });
|
|
389
|
+
fs.writeFileSync(filePath, updated, { mode: 0o600 });
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
export function installCompletion(shell, options = {}) {
|
|
393
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
394
|
+
const platform = options.platform ?? process.platform;
|
|
395
|
+
const completionDir = path.join(homeDir, ".config", "agent-memory", "completions");
|
|
396
|
+
if (shell === "fish") {
|
|
397
|
+
const completionPath = path.join(homeDir, ".config", "fish", "completions", "agent-memory.fish");
|
|
398
|
+
writeCompletionFile(completionPath, generateCompletion(shell));
|
|
399
|
+
return { shell, completionPath, profileUpdated: false };
|
|
400
|
+
}
|
|
401
|
+
const extension = shell === "powershell" ? "ps1" : shell;
|
|
402
|
+
const completionPath = path.join(completionDir, `agent-memory.${extension}`);
|
|
403
|
+
writeCompletionFile(completionPath, generateCompletion(shell));
|
|
404
|
+
if (shell === "bash") {
|
|
405
|
+
const profilePath = path.join(homeDir, ".bashrc");
|
|
406
|
+
const profileUpdated = ensureProfileBlock(profilePath, [
|
|
407
|
+
`if [[ -r "$HOME/.config/agent-memory/completions/agent-memory.bash" ]]; then`,
|
|
408
|
+
` source "$HOME/.config/agent-memory/completions/agent-memory.bash"`,
|
|
409
|
+
"fi",
|
|
410
|
+
]);
|
|
411
|
+
return { shell, completionPath, profilePath, profileUpdated };
|
|
412
|
+
}
|
|
413
|
+
if (shell === "zsh") {
|
|
414
|
+
const profilePath = path.join(homeDir, ".zshrc");
|
|
415
|
+
const profileUpdated = ensureProfileBlock(profilePath, [
|
|
416
|
+
"autoload -Uz compinit",
|
|
417
|
+
"if (( ! $+functions[compdef] )); then compinit; fi",
|
|
418
|
+
`source "$HOME/.config/agent-memory/completions/agent-memory.zsh"`,
|
|
419
|
+
]);
|
|
420
|
+
return { shell, completionPath, profilePath, profileUpdated };
|
|
421
|
+
}
|
|
422
|
+
const profilePath = platform === "win32"
|
|
423
|
+
? path.join(homeDir, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1")
|
|
424
|
+
: path.join(homeDir, ".config", "powershell", "Microsoft.PowerShell_profile.ps1");
|
|
425
|
+
const profileUpdated = ensureProfileBlock(profilePath, [
|
|
426
|
+
`. "$HOME/.config/agent-memory/completions/agent-memory.ps1"`,
|
|
427
|
+
]);
|
|
428
|
+
return { shell, completionPath, profilePath, profileUpdated };
|
|
429
|
+
}
|
package/dist/core.d.ts
CHANGED
package/dist/core.js
CHANGED
|
@@ -1150,13 +1150,22 @@ export async function probeEmbeddings() {
|
|
|
1150
1150
|
}
|
|
1151
1151
|
}
|
|
1152
1152
|
export async function memoryWrite(params) {
|
|
1153
|
-
|
|
1153
|
+
const memoryDir = params.directory ? path.resolve(params.directory) : getMemoryDir();
|
|
1154
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
1155
|
+
fs.mkdirSync(path.join(memoryDir, "daily"), { recursive: true });
|
|
1156
|
+
fs.mkdirSync(path.join(memoryDir, "topics"), { recursive: true });
|
|
1157
|
+
const scheduleSearchRefresh = async () => {
|
|
1158
|
+
if (path.resolve(getMemoryDir()) !== memoryDir)
|
|
1159
|
+
return;
|
|
1160
|
+
await ensureQmdAvailableForUpdate();
|
|
1161
|
+
scheduleQmdUpdate();
|
|
1162
|
+
};
|
|
1154
1163
|
const target = params.target ?? "daily";
|
|
1155
1164
|
const { content, mode } = params;
|
|
1156
1165
|
const sid = shortSessionId(params.sessionId ?? "cli");
|
|
1157
1166
|
const ts = nowTimestamp();
|
|
1158
1167
|
if (target === "daily") {
|
|
1159
|
-
const filePath =
|
|
1168
|
+
const filePath = path.join(memoryDir, "daily", `${params.date?.trim() || todayStr()}.md`);
|
|
1160
1169
|
const existing = readFileSafe(filePath) ?? "";
|
|
1161
1170
|
const safeExisting = redactSecrets(existing).content;
|
|
1162
1171
|
const existingPreview = buildPreview(safeExisting, {
|
|
@@ -1170,8 +1179,7 @@ export async function memoryWrite(params) {
|
|
|
1170
1179
|
const separator = existing.trim() ? "\n\n" : "";
|
|
1171
1180
|
const stored = formatStoredEntry(content, `<!-- ${ts} [${sid}] -->`, params.sourceUri);
|
|
1172
1181
|
fs.writeFileSync(filePath, existing + separator + stored.entry, "utf-8");
|
|
1173
|
-
await
|
|
1174
|
-
scheduleQmdUpdate();
|
|
1182
|
+
await scheduleSearchRefresh();
|
|
1175
1183
|
return {
|
|
1176
1184
|
text: `Appended to daily log: ${filePath}${existingSnippet}`,
|
|
1177
1185
|
details: {
|
|
@@ -1196,7 +1204,7 @@ export async function memoryWrite(params) {
|
|
|
1196
1204
|
if (!slug) {
|
|
1197
1205
|
return { text: "Error: 'topic' must include at least one letter or number.", details: {}, isError: true };
|
|
1198
1206
|
}
|
|
1199
|
-
const filePath =
|
|
1207
|
+
const filePath = path.join(memoryDir, "topics", `${slug}.md`);
|
|
1200
1208
|
const existing = readFileSafe(filePath) ?? "";
|
|
1201
1209
|
const safeExisting = redactSecrets(existing).content;
|
|
1202
1210
|
const existingPreview = buildPreview(safeExisting, {
|
|
@@ -1213,8 +1221,7 @@ export async function memoryWrite(params) {
|
|
|
1213
1221
|
const base = existing.trim() ? existing : header.trimEnd();
|
|
1214
1222
|
const stored = formatStoredEntry(`${content.trim()}\nDaily: [[${linkDate}]]`, `<!-- ${ts} [${sid}] -->`, params.sourceUri);
|
|
1215
1223
|
fs.writeFileSync(filePath, `${base}${separator}${stored.entry}`, "utf-8");
|
|
1216
|
-
await
|
|
1217
|
-
scheduleQmdUpdate();
|
|
1224
|
+
await scheduleSearchRefresh();
|
|
1218
1225
|
return {
|
|
1219
1226
|
text: `Appended to topic: ${filePath}${existingSnippet}`,
|
|
1220
1227
|
details: {
|
|
@@ -1234,7 +1241,7 @@ export async function memoryWrite(params) {
|
|
|
1234
1241
|
};
|
|
1235
1242
|
}
|
|
1236
1243
|
// long_term
|
|
1237
|
-
const memFile =
|
|
1244
|
+
const memFile = path.join(memoryDir, "MEMORY.md");
|
|
1238
1245
|
const existing = readFileSafe(memFile) ?? "";
|
|
1239
1246
|
const safeExisting = redactSecrets(existing).content;
|
|
1240
1247
|
const existingPreview = buildPreview(safeExisting, {
|
|
@@ -1248,8 +1255,7 @@ export async function memoryWrite(params) {
|
|
|
1248
1255
|
if (mode === "overwrite") {
|
|
1249
1256
|
const stored = formatStoredEntry(content, `<!-- last updated: ${ts} [${sid}] -->`, params.sourceUri);
|
|
1250
1257
|
fs.writeFileSync(memFile, stored.entry, "utf-8");
|
|
1251
|
-
await
|
|
1252
|
-
scheduleQmdUpdate();
|
|
1258
|
+
await scheduleSearchRefresh();
|
|
1253
1259
|
return {
|
|
1254
1260
|
text: `Overwrote MEMORY.md${existingSnippet}`,
|
|
1255
1261
|
details: {
|
|
@@ -1269,8 +1275,7 @@ export async function memoryWrite(params) {
|
|
|
1269
1275
|
const separator = existing.trim() ? "\n\n" : "";
|
|
1270
1276
|
const stored = formatStoredEntry(content, `<!-- ${ts} [${sid}] -->`, params.sourceUri);
|
|
1271
1277
|
fs.writeFileSync(memFile, existing + separator + stored.entry, "utf-8");
|
|
1272
|
-
await
|
|
1273
|
-
scheduleQmdUpdate();
|
|
1278
|
+
await scheduleSearchRefresh();
|
|
1274
1279
|
return {
|
|
1275
1280
|
text: `Appended to MEMORY.md${existingSnippet}`,
|
|
1276
1281
|
details: {
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Override the detected home directory in deterministic tests. */
|
|
2
|
+
export declare function _setHookHomeDirForTest(directory: string | null): void;
|
|
3
|
+
export type HookAgentKey = "claude" | "codex" | "cursor" | "opencode" | "pi";
|
|
4
|
+
export interface HookTargetInfo {
|
|
5
|
+
key: HookAgentKey;
|
|
6
|
+
label: string;
|
|
7
|
+
homeMarker: string;
|
|
8
|
+
detectFiles: string[];
|
|
9
|
+
detectCommand?: string;
|
|
10
|
+
supported: boolean;
|
|
11
|
+
unsupportedReason?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DetectedHookTarget extends HookTargetInfo {
|
|
14
|
+
detected: boolean;
|
|
15
|
+
detectReason?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function detectHookAgents(): {
|
|
18
|
+
homeDir: string | null;
|
|
19
|
+
targets: DetectedHookTarget[];
|
|
20
|
+
};
|
|
21
|
+
export interface HookInstallResult {
|
|
22
|
+
key: HookAgentKey;
|
|
23
|
+
label: string;
|
|
24
|
+
installed: boolean;
|
|
25
|
+
path?: string;
|
|
26
|
+
backup?: string;
|
|
27
|
+
reason?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface InstallHooksReport {
|
|
30
|
+
ok: boolean;
|
|
31
|
+
homeDir?: string;
|
|
32
|
+
results: HookInstallResult[];
|
|
33
|
+
error?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function installHooks(agents: Set<HookAgentKey>): InstallHooksReport;
|
|
36
|
+
export interface UninstallHooksReport {
|
|
37
|
+
ok: boolean;
|
|
38
|
+
homeDir?: string;
|
|
39
|
+
results: HookInstallResult[];
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function uninstallHooks(agents?: Set<HookAgentKey>): UninstallHooksReport;
|