akm-opencode 0.0.21 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -6
- package/index.ts +214 -58
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,15 +23,19 @@ Add to your OpenCode config (`opencode.json`):
|
|
|
23
23
|
| `akm_agent` | Dispatch a stash `agent:*` into OpenCode using the stash prompt and metadata |
|
|
24
24
|
| `akm_cmd` | Execute a stash `command:*` template in OpenCode via SDK session prompting |
|
|
25
25
|
| `akm_add` | Install kits from npm, GitHub, git URLs, or local directories |
|
|
26
|
-
| `akm_list` | List
|
|
27
|
-
| `akm_remove` | Remove
|
|
28
|
-
| `akm_update` | Update one
|
|
26
|
+
| `akm_list` | List configured AKM sources |
|
|
27
|
+
| `akm_remove` | Remove a configured AKM source and reindex |
|
|
28
|
+
| `akm_update` | Update one managed source or all managed sources |
|
|
29
29
|
| `akm_clone` | Clone an asset into the working stash or a custom destination for editing |
|
|
30
|
+
| `akm_remember` | Record a memory in the default stash |
|
|
31
|
+
| `akm_feedback` | Record positive or negative feedback for a stash asset |
|
|
30
32
|
| `akm_config` | Get, set, unset, list, or inspect akm configuration (including `config path --all`) |
|
|
31
33
|
| `akm_run` | Execute a stash script using its `run` field |
|
|
32
|
-
| `akm_sources` |
|
|
34
|
+
| `akm_sources` | Backward-compatible alias that lists configured AKM sources |
|
|
33
35
|
| `akm_upgrade` | Check for or install akm CLI updates |
|
|
34
36
|
|
|
37
|
+
The plugin also uses the OpenCode `chat.message` and `tool.execute.after` hooks to record user/system feedback activity and memory usage in OpenCode app logs when relevant.
|
|
38
|
+
|
|
35
39
|
### Registry discovery
|
|
36
40
|
|
|
37
41
|
Use either:
|
|
@@ -75,7 +79,7 @@ At least one of `ref` or `query` is required.
|
|
|
75
79
|
|
|
76
80
|
## Prerequisites
|
|
77
81
|
|
|
78
|
-
|
|
82
|
+
When the plugin loads, it runs `bun install -g akm-cli@latest` so it always picks up the latest published npm package. It then prefers the Bun-installed binary and falls back to an existing `akm` on PATH when needed. It does not run the standalone shell installers automatically.
|
|
79
83
|
|
|
80
84
|
```sh
|
|
81
85
|
# macOS / Linux
|
|
@@ -84,7 +88,7 @@ curl -fsSL https://raw.githubusercontent.com/itlackey/agentikit/main/install.sh
|
|
|
84
88
|
irm https://raw.githubusercontent.com/itlackey/agentikit/main/install.ps1 -OutFile install.ps1; ./install.ps1
|
|
85
89
|
|
|
86
90
|
# Or via Bun
|
|
87
|
-
bun install -g akm-cli
|
|
91
|
+
bun install -g akm-cli@latest
|
|
88
92
|
```
|
|
89
93
|
|
|
90
94
|
## Stash model
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { execFileSync, execSync } from "node:child_process"
|
|
|
3
3
|
import path from "node:path"
|
|
4
4
|
|
|
5
5
|
let resolvedAkmCommand = "akm"
|
|
6
|
-
|
|
6
|
+
const autoInstallPackageRef = "akm-cli@latest"
|
|
7
7
|
|
|
8
8
|
type LogLevel = "debug" | "info" | "warn" | "error"
|
|
9
9
|
|
|
@@ -77,59 +77,84 @@ function getCommandStatus(command: string): "ok" | "missing" | "error" {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
function
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
function getBunGlobalAkmCommand(): string | null {
|
|
81
|
+
try {
|
|
82
|
+
const globalBin = execFileSync("bun", ["pm", "bin", "-g"], {
|
|
83
|
+
encoding: "utf8",
|
|
84
|
+
timeout: 10_000,
|
|
85
|
+
}).trim()
|
|
86
|
+
if (!globalBin || !path.isAbsolute(globalBin)) return null
|
|
87
|
+
return process.platform === "win32"
|
|
88
|
+
? path.join(globalBin, "akm.exe")
|
|
89
|
+
: path.join(globalBin, "akm")
|
|
90
|
+
} catch {
|
|
91
|
+
return null
|
|
86
92
|
}
|
|
87
|
-
|
|
93
|
+
}
|
|
88
94
|
|
|
95
|
+
async function ensureLatestAkmInstalled(client: LogCapableClient): Promise<void> {
|
|
89
96
|
try {
|
|
90
97
|
execFileSync("bun", ["--version"], {
|
|
91
98
|
encoding: "utf8",
|
|
92
99
|
timeout: 10_000,
|
|
93
100
|
})
|
|
94
|
-
} catch {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
} catch (error: unknown) {
|
|
102
|
+
await writePluginLog(client, "warn", "AKM auto-install skipped", {
|
|
103
|
+
subsystem: "akm",
|
|
104
|
+
installer: "bun",
|
|
105
|
+
error: `Bun is not available: ${formatCliError(error)}`,
|
|
106
|
+
})
|
|
107
|
+
return
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
try {
|
|
102
|
-
execFileSync("bun", ["install", "-g",
|
|
111
|
+
execFileSync("bun", ["install", "-g", autoInstallPackageRef], {
|
|
103
112
|
encoding: "utf8",
|
|
104
113
|
timeout: 120_000,
|
|
105
114
|
stdio: "pipe",
|
|
106
115
|
})
|
|
107
116
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const candidate = path.join(globalBin, process.platform === "win32" ? "akm.exe" : "akm")
|
|
114
|
-
if (getCommandStatus(candidate) === "ok") {
|
|
115
|
-
resolvedAkmCommand = candidate
|
|
116
|
-
return resolvedAkmCommand
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (getCommandStatus("akm") === "ok") {
|
|
117
|
+
const bunGlobalAkm = getBunGlobalAkmCommand()
|
|
118
|
+
if (bunGlobalAkm && getCommandStatus(bunGlobalAkm) === "ok") {
|
|
119
|
+
resolvedAkmCommand = bunGlobalAkm
|
|
120
|
+
} else if (getCommandStatus("akm") === "ok") {
|
|
120
121
|
resolvedAkmCommand = "akm"
|
|
121
|
-
return resolvedAkmCommand
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
await writePluginLog(client, "info", "AKM CLI install check completed", {
|
|
125
|
+
subsystem: "akm",
|
|
126
|
+
installer: "bun",
|
|
127
|
+
package: autoInstallPackageRef,
|
|
128
|
+
command: resolvedAkmCommand,
|
|
129
|
+
})
|
|
128
130
|
} catch (error: unknown) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
await writePluginLog(client, "warn", "AKM auto-install failed", {
|
|
132
|
+
subsystem: "akm",
|
|
133
|
+
installer: "bun",
|
|
134
|
+
package: autoInstallPackageRef,
|
|
135
|
+
error: formatCliError(error),
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function resolveAkmCommand(): string | CliError {
|
|
141
|
+
const currentStatus = getCommandStatus(resolvedAkmCommand)
|
|
142
|
+
if (currentStatus === "ok" || currentStatus === "error") return resolvedAkmCommand
|
|
143
|
+
|
|
144
|
+
const bunGlobalAkm = getBunGlobalAkmCommand()
|
|
145
|
+
if (bunGlobalAkm && getCommandStatus(bunGlobalAkm) === "ok") {
|
|
146
|
+
resolvedAkmCommand = bunGlobalAkm
|
|
147
|
+
return resolvedAkmCommand
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (getCommandStatus("akm") === "ok") {
|
|
151
|
+
resolvedAkmCommand = "akm"
|
|
152
|
+
return resolvedAkmCommand
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
ok: false,
|
|
157
|
+
error: `The 'akm' CLI could not be resolved after attempting to install '${autoInstallPackageRef}' with Bun. Install akm from https://github.com/itlackey/agentikit.`,
|
|
133
158
|
}
|
|
134
159
|
}
|
|
135
160
|
|
|
@@ -187,7 +212,7 @@ async function runCli(client: LogCapableClient, args: string[], meta: CliLogMeta
|
|
|
187
212
|
}
|
|
188
213
|
|
|
189
214
|
type CliError = { ok: false; error: string }
|
|
190
|
-
type AssetType = "
|
|
215
|
+
type AssetType = "agent" | "command" | "knowledge" | "memory" | "script" | "skill"
|
|
191
216
|
|
|
192
217
|
type ShowAgentResponse = {
|
|
193
218
|
type: "agent"
|
|
@@ -251,7 +276,7 @@ type SearchHit = {
|
|
|
251
276
|
|
|
252
277
|
type SearchResponse = {
|
|
253
278
|
hits?: SearchHit[]
|
|
254
|
-
source?: "local" | "registry" | "both"
|
|
279
|
+
source?: "local" | "stash" | "registry" | "both"
|
|
255
280
|
stashDir?: string
|
|
256
281
|
timing?: { totalMs?: number; rankMs?: number; embedMs?: number }
|
|
257
282
|
warnings?: string[]
|
|
@@ -351,6 +376,59 @@ function extractText(parts: unknown): string {
|
|
|
351
376
|
return segments.join("\n\n")
|
|
352
377
|
}
|
|
353
378
|
|
|
379
|
+
function parseToolOutput(raw: string): unknown {
|
|
380
|
+
try {
|
|
381
|
+
return JSON.parse(raw)
|
|
382
|
+
} catch {
|
|
383
|
+
return undefined
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function extractMemoryRefs(toolName: string, args: Record<string, unknown>, value: unknown): string[] {
|
|
388
|
+
const refs = new Set<string>()
|
|
389
|
+
const parsed = value && typeof value === "object" ? value as {
|
|
390
|
+
type?: unknown
|
|
391
|
+
ref?: unknown
|
|
392
|
+
name?: unknown
|
|
393
|
+
hits?: unknown
|
|
394
|
+
} : undefined
|
|
395
|
+
|
|
396
|
+
if (toolName === "akm_remember" && typeof parsed?.ref === "string" && parsed.ref) {
|
|
397
|
+
refs.add(parsed.ref)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (parsed?.type === "memory") {
|
|
401
|
+
if (typeof parsed.ref === "string" && parsed.ref) refs.add(parsed.ref)
|
|
402
|
+
if (typeof args.ref === "string" && args.ref) refs.add(args.ref)
|
|
403
|
+
if (refs.size === 0 && typeof parsed.name === "string" && parsed.name) refs.add(`memory:${parsed.name}`)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (Array.isArray(parsed?.hits)) {
|
|
407
|
+
for (const hit of parsed.hits) {
|
|
408
|
+
if (!hit || typeof hit !== "object") continue
|
|
409
|
+
if ((hit as { type?: unknown }).type !== "memory") continue
|
|
410
|
+
const ref = (hit as { ref?: unknown }).ref
|
|
411
|
+
if (typeof ref === "string" && ref) refs.add(ref)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return [...refs]
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function classifyToolFeedback(value: unknown): "positive" | "negative" | undefined {
|
|
419
|
+
if (!value || typeof value !== "object") return undefined
|
|
420
|
+
if (isCliError(value)) return "negative"
|
|
421
|
+
if ("ok" in value && (value as { ok?: unknown }).ok === false) return "negative"
|
|
422
|
+
if ("error" in value && typeof (value as { error?: unknown }).error === "string") return "negative"
|
|
423
|
+
if ("ok" in value && (value as { ok?: unknown }).ok === true) return "positive"
|
|
424
|
+
if ("type" in value || "hits" in value || "assetHits" in value || "sources" in value) return "positive"
|
|
425
|
+
return undefined
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function truncateLogText(value: string, limit = 1_000): string {
|
|
429
|
+
return value.length > limit ? `${value.slice(0, limit)}…` : value
|
|
430
|
+
}
|
|
431
|
+
|
|
354
432
|
async function resolveRefInput(
|
|
355
433
|
client: LogCapableClient,
|
|
356
434
|
input: { ref?: string; query?: string },
|
|
@@ -366,7 +444,7 @@ async function resolveRefInput(
|
|
|
366
444
|
return { ok: false, error: "Provide either 'ref' or 'query'." }
|
|
367
445
|
}
|
|
368
446
|
|
|
369
|
-
const raw = await runCli(client, ["search", query, "--type", type, "--limit", "1", "--detail", "normal", "--source", "
|
|
447
|
+
const raw = await runCli(client, ["search", query, "--type", type, "--limit", "1", "--detail", "normal", "--source", "stash"], meta)
|
|
370
448
|
const parsed = parseCliJson<SearchResponse>(raw)
|
|
371
449
|
if (isCliError(parsed)) return parsed
|
|
372
450
|
|
|
@@ -415,20 +493,24 @@ function renderCommandTemplate(template: string, rawArguments: string): string {
|
|
|
415
493
|
.replace(/\$(\d+)/g, (_m, index: string) => args[Number(index) - 1] ?? "")
|
|
416
494
|
}
|
|
417
495
|
|
|
496
|
+
function normalizeSearchSource(source: "local" | "stash" | "registry" | "both"): "stash" | "registry" | "both" {
|
|
497
|
+
return source === "local" ? "stash" : source
|
|
498
|
+
}
|
|
499
|
+
|
|
418
500
|
function createSearchArgs(input: {
|
|
419
501
|
query: string
|
|
420
502
|
type?: AssetType | "any"
|
|
421
503
|
limit?: number
|
|
422
|
-
source?: "local" | "registry" | "both"
|
|
423
|
-
defaultSource?: "local" | "registry" | "both"
|
|
504
|
+
source?: "local" | "stash" | "registry" | "both"
|
|
505
|
+
defaultSource?: "local" | "stash" | "registry" | "both"
|
|
424
506
|
}): string[] {
|
|
425
507
|
const args = ["search", input.query]
|
|
426
508
|
if (input.type) args.push("--type", input.type)
|
|
427
509
|
if (input.limit) args.push("--limit", String(input.limit))
|
|
428
510
|
if (input.source) {
|
|
429
|
-
args.push("--source", input.source)
|
|
511
|
+
args.push("--source", normalizeSearchSource(input.source))
|
|
430
512
|
} else if (input.defaultSource) {
|
|
431
|
-
args.push("--source", input.defaultSource)
|
|
513
|
+
args.push("--source", normalizeSearchSource(input.defaultSource))
|
|
432
514
|
}
|
|
433
515
|
args.push("--detail", "normal")
|
|
434
516
|
return args
|
|
@@ -454,21 +536,67 @@ type PluginClient = {
|
|
|
454
536
|
}
|
|
455
537
|
}
|
|
456
538
|
|
|
457
|
-
export const AgentikitPlugin: Plugin = async ({ client }) =>
|
|
458
|
-
|
|
539
|
+
export const AgentikitPlugin: Plugin = async ({ client }) => {
|
|
540
|
+
await ensureLatestAkmInstalled(client as unknown as LogCapableClient)
|
|
541
|
+
|
|
542
|
+
return {
|
|
543
|
+
"chat.message": async (input, output) => {
|
|
544
|
+
const text = extractText(output.parts).trim()
|
|
545
|
+
if (!text) return
|
|
546
|
+
await writePluginLog(client as unknown as LogCapableClient, "info", "AKM user feedback recorded", {
|
|
547
|
+
subsystem: "feedback",
|
|
548
|
+
actor: "user",
|
|
549
|
+
sessionID: input.sessionID,
|
|
550
|
+
messageID: input.messageID,
|
|
551
|
+
agent: input.agent,
|
|
552
|
+
text: truncateLogText(text),
|
|
553
|
+
})
|
|
554
|
+
},
|
|
555
|
+
"tool.execute.after": async (input, output) => {
|
|
556
|
+
if (!input.tool.startsWith("akm_")) return
|
|
557
|
+
|
|
558
|
+
const parsed = parseToolOutput(output.output)
|
|
559
|
+
if (!parsed) return
|
|
560
|
+
|
|
561
|
+
const feedback = classifyToolFeedback(parsed)
|
|
562
|
+
if (feedback) {
|
|
563
|
+
await writePluginLog(client as unknown as LogCapableClient, feedback === "negative" ? "warn" : "info", "AKM system feedback recorded", {
|
|
564
|
+
subsystem: "feedback",
|
|
565
|
+
actor: "system",
|
|
566
|
+
feedback,
|
|
567
|
+
toolName: input.tool,
|
|
568
|
+
sessionID: input.sessionID,
|
|
569
|
+
callID: input.callID,
|
|
570
|
+
title: output.title,
|
|
571
|
+
error: typeof (parsed as { error?: unknown }).error === "string" ? (parsed as { error?: string }).error : undefined,
|
|
572
|
+
})
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const memoryRefs = extractMemoryRefs(input.tool, input.args as Record<string, unknown>, parsed)
|
|
576
|
+
if (memoryRefs.length > 0) {
|
|
577
|
+
await writePluginLog(client as unknown as LogCapableClient, "info", "AKM memory usage recorded", {
|
|
578
|
+
subsystem: "memory",
|
|
579
|
+
toolName: input.tool,
|
|
580
|
+
sessionID: input.sessionID,
|
|
581
|
+
callID: input.callID,
|
|
582
|
+
refs: memoryRefs,
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
},
|
|
586
|
+
tool: {
|
|
459
587
|
akm_search: tool({
|
|
460
|
-
description: "Search your
|
|
588
|
+
description: "Search your stash or the akm registry for scripts, skills, commands, agents, knowledge, and memories. Use source='registry' or akm_registry_search for installable community kits.",
|
|
461
589
|
args: {
|
|
462
590
|
query: tool.schema.string().describe("Case-insensitive substring search."),
|
|
463
591
|
type: tool.schema
|
|
464
|
-
.enum(["
|
|
592
|
+
.enum(["agent", "command", "knowledge", "memory", "script", "skill", "any"])
|
|
465
593
|
.optional()
|
|
466
594
|
.describe("Optional type filter. Defaults to 'any'."),
|
|
467
595
|
limit: tool.schema.number().optional().describe("Maximum number of hits to return. Defaults to 20."),
|
|
468
596
|
source: tool.schema
|
|
469
|
-
.enum(["local", "registry", "both"])
|
|
597
|
+
.enum(["local", "stash", "registry", "both"])
|
|
470
598
|
.optional()
|
|
471
|
-
.describe("Search source. '
|
|
599
|
+
.describe("Search source. 'stash' searches local stash directories, 'registry' searches registries, and 'both' searches all sources. 'local' remains a backward-compatible alias for 'stash'."),
|
|
472
600
|
},
|
|
473
601
|
async execute({ query, type, limit, source }) {
|
|
474
602
|
return runCli(client as unknown as LogCapableClient, createSearchArgs({ query, type, limit, source }), { toolName: "akm_search" })
|
|
@@ -479,7 +607,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
479
607
|
args: {
|
|
480
608
|
query: tool.schema.string().describe("Search query for installable registry kits."),
|
|
481
609
|
type: tool.schema
|
|
482
|
-
.enum(["
|
|
610
|
+
.enum(["agent", "command", "knowledge", "memory", "script", "skill", "any"])
|
|
483
611
|
.optional()
|
|
484
612
|
.describe("Optional asset type filter. Defaults to 'any'."),
|
|
485
613
|
limit: tool.schema.number().optional().describe("Maximum number of registry hits to return. Defaults to 20."),
|
|
@@ -554,25 +682,25 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
554
682
|
},
|
|
555
683
|
}),
|
|
556
684
|
akm_list: tool({
|
|
557
|
-
description: "List all kits
|
|
685
|
+
description: "List all configured AKM sources, including local directories, managed kits, and remote providers.",
|
|
558
686
|
args: {},
|
|
559
687
|
async execute() {
|
|
560
688
|
return runCli(client as unknown as LogCapableClient, ["list"], { toolName: "akm_list" })
|
|
561
689
|
},
|
|
562
690
|
}),
|
|
563
691
|
akm_remove: tool({
|
|
564
|
-
description: "Remove
|
|
692
|
+
description: "Remove a configured AKM source by id, ref, path, URL, or name and reindex the stash.",
|
|
565
693
|
args: {
|
|
566
|
-
package_ref: tool.schema.string().describe("
|
|
694
|
+
package_ref: tool.schema.string().describe("Source id, ref, path, URL, or name, such as npm:@scope/kit, owner/repo, or ~/.claude/skills."),
|
|
567
695
|
},
|
|
568
696
|
async execute({ package_ref }) {
|
|
569
697
|
return runCli(client as unknown as LogCapableClient, ["remove", package_ref], { toolName: "akm_remove" })
|
|
570
698
|
},
|
|
571
699
|
}),
|
|
572
700
|
akm_update: tool({
|
|
573
|
-
description: "Update one
|
|
701
|
+
description: "Update one managed AKM source or all managed sources to the latest available version.",
|
|
574
702
|
args: {
|
|
575
|
-
package_ref: tool.schema.string().optional().describe("
|
|
703
|
+
package_ref: tool.schema.string().optional().describe("Managed source id or ref to update."),
|
|
576
704
|
all: tool.schema.boolean().optional().describe("Update all installed kits."),
|
|
577
705
|
force: tool.schema.boolean().optional().describe("Force a fresh download even if the version is unchanged."),
|
|
578
706
|
},
|
|
@@ -606,6 +734,33 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
606
734
|
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_clone" })
|
|
607
735
|
},
|
|
608
736
|
}),
|
|
737
|
+
akm_remember: tool({
|
|
738
|
+
description: "Record a memory in the default AKM stash so it can be searched and shown later.",
|
|
739
|
+
args: {
|
|
740
|
+
content: tool.schema.string().describe("Memory content to store."),
|
|
741
|
+
name: tool.schema.string().optional().describe("Optional memory name."),
|
|
742
|
+
force: tool.schema.boolean().optional().describe("Overwrite an existing memory with the same name."),
|
|
743
|
+
},
|
|
744
|
+
async execute({ content, name, force }) {
|
|
745
|
+
const args = ["remember", content]
|
|
746
|
+
if (name) args.push("--name", name)
|
|
747
|
+
if (force) args.push("--force")
|
|
748
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_remember" })
|
|
749
|
+
},
|
|
750
|
+
}),
|
|
751
|
+
akm_feedback: tool({
|
|
752
|
+
description: "Record positive or negative feedback for a stash asset so AKM can improve future ranking.",
|
|
753
|
+
args: {
|
|
754
|
+
ref: tool.schema.string().describe("Asset ref to record feedback for."),
|
|
755
|
+
sentiment: tool.schema.enum(["positive", "negative"]).describe("Whether the feedback is positive or negative."),
|
|
756
|
+
note: tool.schema.string().optional().describe("Optional note to attach to the feedback."),
|
|
757
|
+
},
|
|
758
|
+
async execute({ ref, sentiment, note }) {
|
|
759
|
+
const args = ["feedback", ref, sentiment === "positive" ? "--positive" : "--negative"]
|
|
760
|
+
if (note) args.push("--note", note)
|
|
761
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_feedback" })
|
|
762
|
+
},
|
|
763
|
+
}),
|
|
609
764
|
akm_agent: tool({
|
|
610
765
|
description: "Dispatch a stash agent by ref into a child OpenCode session, applying the agent prompt and metadata from akm_show.",
|
|
611
766
|
args: {
|
|
@@ -843,10 +998,10 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
843
998
|
},
|
|
844
999
|
}),
|
|
845
1000
|
akm_sources: tool({
|
|
846
|
-
description: "List all
|
|
1001
|
+
description: "List all configured AKM sources. Kept as a backward-compatible alias for the older sources command.",
|
|
847
1002
|
args: {},
|
|
848
1003
|
async execute() {
|
|
849
|
-
return runCli(client as unknown as LogCapableClient, ["
|
|
1004
|
+
return runCli(client as unknown as LogCapableClient, ["list"], { toolName: "akm_sources" })
|
|
850
1005
|
},
|
|
851
1006
|
}),
|
|
852
1007
|
akm_upgrade: tool({
|
|
@@ -862,5 +1017,6 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
862
1017
|
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_upgrade" })
|
|
863
1018
|
},
|
|
864
1019
|
}),
|
|
865
|
-
|
|
866
|
-
}
|
|
1020
|
+
},
|
|
1021
|
+
}
|
|
1022
|
+
}
|