akm-opencode 0.0.18 → 0.0.21
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 +1 -1
- package/index.ts +127 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ Use either:
|
|
|
39
39
|
- `akm_search` with `source: "registry"` or `source: "both"`
|
|
40
40
|
- `akm_registry_search` when you only want installable community kits
|
|
41
41
|
|
|
42
|
-
Registry hits include `id` and `action` fields. Use `assets: true` when you also want asset-level matches from registry v2 indexes.
|
|
42
|
+
Registry hits include `id`, `installRef`, and `action` fields. Use `installRef` when passing a result into `akm_add`; registry-specific IDs are not installable refs. Use `assets: true` when you also want asset-level matches from registry v2 indexes.
|
|
43
43
|
|
|
44
44
|
## Agent Dispatch
|
|
45
45
|
|
package/index.ts
CHANGED
|
@@ -5,6 +5,28 @@ import path from "node:path"
|
|
|
5
5
|
let resolvedAkmCommand = "akm"
|
|
6
6
|
let attemptedAutoInstall = false
|
|
7
7
|
|
|
8
|
+
type LogLevel = "debug" | "info" | "warn" | "error"
|
|
9
|
+
|
|
10
|
+
type LogCapableClient = {
|
|
11
|
+
app: {
|
|
12
|
+
log: (options: {
|
|
13
|
+
query?: { directory?: string }
|
|
14
|
+
body: {
|
|
15
|
+
service: string
|
|
16
|
+
level: LogLevel
|
|
17
|
+
message: string
|
|
18
|
+
extra?: Record<string, unknown>
|
|
19
|
+
}
|
|
20
|
+
}) => Promise<unknown>
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type CliLogMeta = {
|
|
25
|
+
toolName: string
|
|
26
|
+
directory?: string
|
|
27
|
+
sessionID?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
8
30
|
function formatCliError(error: unknown): string {
|
|
9
31
|
if (error && typeof error === "object" && "code" in error && (error as { code?: unknown }).code === "ENOENT") {
|
|
10
32
|
return "The 'akm' CLI was not found on PATH. Install it first from https://github.com/itlackey/agentikit."
|
|
@@ -12,6 +34,34 @@ function formatCliError(error: unknown): string {
|
|
|
12
34
|
return error instanceof Error ? error.message : String(error)
|
|
13
35
|
}
|
|
14
36
|
|
|
37
|
+
function toLogString(value: unknown): string | undefined {
|
|
38
|
+
if (typeof value === "string") return value
|
|
39
|
+
if (value instanceof Buffer) return value.toString("utf8")
|
|
40
|
+
return undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getExecStatus(error: unknown): number | null {
|
|
44
|
+
if (!error || typeof error !== "object" || !("status" in error)) return null
|
|
45
|
+
const status = (error as { status?: unknown }).status
|
|
46
|
+
return typeof status === "number" ? status : null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function writePluginLog(client: LogCapableClient, level: LogLevel, message: string, extra: Record<string, unknown>) {
|
|
50
|
+
try {
|
|
51
|
+
await client.app.log({
|
|
52
|
+
query: typeof extra.directory === "string" ? { directory: extra.directory } : undefined,
|
|
53
|
+
body: {
|
|
54
|
+
service: "akm-opencode",
|
|
55
|
+
level,
|
|
56
|
+
message,
|
|
57
|
+
extra,
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
} catch {
|
|
61
|
+
// Avoid breaking the TUI if logging itself fails.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
15
65
|
function getCommandStatus(command: string): "ok" | "missing" | "error" {
|
|
16
66
|
try {
|
|
17
67
|
execFileSync(command, ["--version"], {
|
|
@@ -83,17 +133,55 @@ function resolveAkmCommand(): string | CliError {
|
|
|
83
133
|
}
|
|
84
134
|
}
|
|
85
135
|
|
|
86
|
-
function runCli(args: string[]): string {
|
|
136
|
+
async function runCli(client: LogCapableClient, args: string[], meta: CliLogMeta): Promise<string> {
|
|
87
137
|
const command = resolveAkmCommand()
|
|
88
|
-
if (typeof command !== "string")
|
|
138
|
+
if (typeof command !== "string") {
|
|
139
|
+
await writePluginLog(client, "error", "AKM command resolution failed", {
|
|
140
|
+
subsystem: "akm",
|
|
141
|
+
toolName: meta.toolName,
|
|
142
|
+
sessionID: meta.sessionID,
|
|
143
|
+
directory: meta.directory,
|
|
144
|
+
command: resolvedAkmCommand,
|
|
145
|
+
args,
|
|
146
|
+
exitCode: null,
|
|
147
|
+
stdout: "",
|
|
148
|
+
stderr: command.error,
|
|
149
|
+
})
|
|
150
|
+
return JSON.stringify(command)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const fullArgs = [...args, "--format", "json"]
|
|
89
154
|
|
|
90
155
|
try {
|
|
91
|
-
|
|
156
|
+
const stdout = execFileSync(command, fullArgs, {
|
|
92
157
|
encoding: "utf8",
|
|
93
158
|
timeout: 60_000,
|
|
94
159
|
})
|
|
160
|
+
await writePluginLog(client, "info", "AKM command completed", {
|
|
161
|
+
subsystem: "akm",
|
|
162
|
+
toolName: meta.toolName,
|
|
163
|
+
sessionID: meta.sessionID,
|
|
164
|
+
directory: meta.directory,
|
|
165
|
+
command,
|
|
166
|
+
args: fullArgs,
|
|
167
|
+
exitCode: 0,
|
|
168
|
+
stdout,
|
|
169
|
+
stderr: "",
|
|
170
|
+
})
|
|
171
|
+
return stdout
|
|
95
172
|
} catch (error: unknown) {
|
|
96
173
|
const message = formatCliError(error)
|
|
174
|
+
await writePluginLog(client, "error", "AKM command failed", {
|
|
175
|
+
subsystem: "akm",
|
|
176
|
+
toolName: meta.toolName,
|
|
177
|
+
sessionID: meta.sessionID,
|
|
178
|
+
directory: meta.directory,
|
|
179
|
+
command,
|
|
180
|
+
args: fullArgs,
|
|
181
|
+
exitCode: getExecStatus(error),
|
|
182
|
+
stdout: toLogString((error as { stdout?: unknown }).stdout) ?? "",
|
|
183
|
+
stderr: toLogString((error as { stderr?: unknown }).stderr) ?? message,
|
|
184
|
+
})
|
|
97
185
|
return JSON.stringify({ ok: false, error: message })
|
|
98
186
|
}
|
|
99
187
|
}
|
|
@@ -147,6 +235,7 @@ type SearchHit = {
|
|
|
147
235
|
type: AssetType | "registry" | "registry-asset"
|
|
148
236
|
ref?: string
|
|
149
237
|
id?: string
|
|
238
|
+
installRef?: string
|
|
150
239
|
editable?: boolean
|
|
151
240
|
name?: string
|
|
152
241
|
description?: string
|
|
@@ -262,7 +351,12 @@ function extractText(parts: unknown): string {
|
|
|
262
351
|
return segments.join("\n\n")
|
|
263
352
|
}
|
|
264
353
|
|
|
265
|
-
function resolveRefInput(
|
|
354
|
+
async function resolveRefInput(
|
|
355
|
+
client: LogCapableClient,
|
|
356
|
+
input: { ref?: string; query?: string },
|
|
357
|
+
type: AssetType,
|
|
358
|
+
meta: CliLogMeta,
|
|
359
|
+
): Promise<{ ok: true; ref: string } | CliError> {
|
|
266
360
|
if (input.ref && input.ref.trim()) {
|
|
267
361
|
return { ok: true, ref: input.ref.trim() }
|
|
268
362
|
}
|
|
@@ -272,7 +366,7 @@ function resolveRefInput(input: { ref?: string; query?: string }, type: AssetTyp
|
|
|
272
366
|
return { ok: false, error: "Provide either 'ref' or 'query'." }
|
|
273
367
|
}
|
|
274
368
|
|
|
275
|
-
const raw = runCli(["search", query, "--type", type, "--limit", "1", "--detail", "normal", "--source", "local"])
|
|
369
|
+
const raw = await runCli(client, ["search", query, "--type", type, "--limit", "1", "--detail", "normal", "--source", "local"], meta)
|
|
276
370
|
const parsed = parseCliJson<SearchResponse>(raw)
|
|
277
371
|
if (isCliError(parsed)) return parsed
|
|
278
372
|
|
|
@@ -377,7 +471,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
377
471
|
.describe("Search source. 'local' searches stash dirs, 'registry' searches npm/GitHub, 'both' searches all. Defaults to 'local'."),
|
|
378
472
|
},
|
|
379
473
|
async execute({ query, type, limit, source }) {
|
|
380
|
-
return runCli(createSearchArgs({ query, type, limit, source }))
|
|
474
|
+
return runCli(client as unknown as LogCapableClient, createSearchArgs({ query, type, limit, source }), { toolName: "akm_search" })
|
|
381
475
|
},
|
|
382
476
|
}),
|
|
383
477
|
akm_registry_search: tool({
|
|
@@ -397,7 +491,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
397
491
|
const assetTypeFilter = type && type !== "any" ? type : undefined
|
|
398
492
|
if (assets || assetTypeFilter) args.push("--assets")
|
|
399
493
|
|
|
400
|
-
const raw = runCli(args)
|
|
494
|
+
const raw = await runCli(client as unknown as LogCapableClient, args, { toolName: "akm_registry_search" })
|
|
401
495
|
if (!assetTypeFilter) return raw
|
|
402
496
|
|
|
403
497
|
const parsed = parseCliJson<{
|
|
@@ -440,14 +534,14 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
440
534
|
if (end_line != null) args.push(String(end_line))
|
|
441
535
|
}
|
|
442
536
|
}
|
|
443
|
-
return runCli(args)
|
|
537
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_show" })
|
|
444
538
|
},
|
|
445
539
|
}),
|
|
446
540
|
akm_index: tool({
|
|
447
541
|
description: "Build or rebuild the akm stash index. Scans stash directories, generates missing .stash.json metadata, and builds a semantic search index.",
|
|
448
542
|
args: {},
|
|
449
543
|
async execute() {
|
|
450
|
-
return runCli(["index"])
|
|
544
|
+
return runCli(client as unknown as LogCapableClient, ["index"], { toolName: "akm_index" })
|
|
451
545
|
},
|
|
452
546
|
}),
|
|
453
547
|
akm_add: tool({
|
|
@@ -456,14 +550,14 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
456
550
|
package_ref: tool.schema.string().describe("Package reference such as npm:@scope/kit, github:<owner>/<repo>, git+https://host/repo, or ./local/kit."),
|
|
457
551
|
},
|
|
458
552
|
async execute({ package_ref }) {
|
|
459
|
-
return runCli(["add", package_ref])
|
|
553
|
+
return runCli(client as unknown as LogCapableClient, ["add", package_ref], { toolName: "akm_add" })
|
|
460
554
|
},
|
|
461
555
|
}),
|
|
462
556
|
akm_list: tool({
|
|
463
557
|
description: "List all kits installed from the registry.",
|
|
464
558
|
args: {},
|
|
465
559
|
async execute() {
|
|
466
|
-
return runCli(["list"])
|
|
560
|
+
return runCli(client as unknown as LogCapableClient, ["list"], { toolName: "akm_list" })
|
|
467
561
|
},
|
|
468
562
|
}),
|
|
469
563
|
akm_remove: tool({
|
|
@@ -472,7 +566,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
472
566
|
package_ref: tool.schema.string().describe("Installed kit id or ref, such as npm:@scope/kit or owner/repo."),
|
|
473
567
|
},
|
|
474
568
|
async execute({ package_ref }) {
|
|
475
|
-
return runCli(["remove", package_ref])
|
|
569
|
+
return runCli(client as unknown as LogCapableClient, ["remove", package_ref], { toolName: "akm_remove" })
|
|
476
570
|
},
|
|
477
571
|
}),
|
|
478
572
|
akm_update: tool({
|
|
@@ -493,7 +587,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
493
587
|
return JSON.stringify({ ok: false, error: "Provide 'package_ref' or set 'all' to true." })
|
|
494
588
|
}
|
|
495
589
|
if (force) args.push("--force")
|
|
496
|
-
return runCli(args)
|
|
590
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_update" })
|
|
497
591
|
},
|
|
498
592
|
}),
|
|
499
593
|
akm_clone: tool({
|
|
@@ -509,7 +603,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
509
603
|
if (name) args.push("--name", name)
|
|
510
604
|
if (dest) args.push("--dest", dest)
|
|
511
605
|
if (force) args.push("--force")
|
|
512
|
-
return runCli(args)
|
|
606
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_clone" })
|
|
513
607
|
},
|
|
514
608
|
}),
|
|
515
609
|
akm_agent: tool({
|
|
@@ -522,10 +616,15 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
522
616
|
as_subtask: tool.schema.boolean().optional().describe("Run in child session with parent context. Defaults to true."),
|
|
523
617
|
},
|
|
524
618
|
async execute({ ref, query, task_prompt, dispatch_agent, as_subtask }, context) {
|
|
525
|
-
const
|
|
619
|
+
const logMeta = {
|
|
620
|
+
toolName: "akm_agent",
|
|
621
|
+
directory: context.directory,
|
|
622
|
+
sessionID: context.sessionID,
|
|
623
|
+
}
|
|
624
|
+
const resolved = await resolveRefInput(client as unknown as LogCapableClient, { ref, query }, "agent", logMeta)
|
|
526
625
|
if (!resolved.ok) return JSON.stringify(resolved)
|
|
527
626
|
|
|
528
|
-
const shownRaw = runCli(["show", resolved.ref])
|
|
627
|
+
const shownRaw = await runCli(client as unknown as LogCapableClient, ["show", resolved.ref], logMeta)
|
|
529
628
|
const shown = parseCliJson<ShowAgentResponse | { type: string }>(shownRaw)
|
|
530
629
|
if (isCliError(shown)) {
|
|
531
630
|
return JSON.stringify(shown)
|
|
@@ -609,10 +708,15 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
609
708
|
as_subtask: tool.schema.boolean().optional().describe("Run in child session with parent context. Defaults to false."),
|
|
610
709
|
},
|
|
611
710
|
async execute({ ref, query, arguments: commandArguments, dispatch_agent, as_subtask }, context) {
|
|
612
|
-
const
|
|
711
|
+
const logMeta = {
|
|
712
|
+
toolName: "akm_cmd",
|
|
713
|
+
directory: context.directory,
|
|
714
|
+
sessionID: context.sessionID,
|
|
715
|
+
}
|
|
716
|
+
const resolved = await resolveRefInput(client as unknown as LogCapableClient, { ref, query }, "command", logMeta)
|
|
613
717
|
if (!resolved.ok) return JSON.stringify(resolved)
|
|
614
718
|
|
|
615
|
-
const shownRaw = runCli(["show", resolved.ref])
|
|
719
|
+
const shownRaw = await runCli(client as unknown as LogCapableClient, ["show", resolved.ref], logMeta)
|
|
616
720
|
const shown = parseCliJson<ShowCommandResponse | { type: string }>(shownRaw)
|
|
617
721
|
if (isCliError(shown)) return JSON.stringify(shown)
|
|
618
722
|
if (!isShowCommandResponse(shown)) {
|
|
@@ -680,7 +784,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
680
784
|
if (key) args.push(key)
|
|
681
785
|
if (value) args.push(value)
|
|
682
786
|
if (action === "path" && all) args.push("--all")
|
|
683
|
-
return runCli(args)
|
|
787
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_config" })
|
|
684
788
|
},
|
|
685
789
|
}),
|
|
686
790
|
akm_run: tool({
|
|
@@ -691,10 +795,10 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
691
795
|
args: tool.schema.string().optional().describe("Arguments to append to the run command."),
|
|
692
796
|
},
|
|
693
797
|
async execute({ ref, query, args: runArgs }) {
|
|
694
|
-
const resolved = resolveRefInput({ ref, query }, "script")
|
|
798
|
+
const resolved = await resolveRefInput(client as unknown as LogCapableClient, { ref, query }, "script", { toolName: "akm_run" })
|
|
695
799
|
if (!resolved.ok) return JSON.stringify(resolved)
|
|
696
800
|
|
|
697
|
-
const shownRaw = runCli(["show", resolved.ref])
|
|
801
|
+
const shownRaw = await runCli(client as unknown as LogCapableClient, ["show", resolved.ref], { toolName: "akm_run" })
|
|
698
802
|
const shown = parseCliJson<ShowToolResponse | { type: string }>(shownRaw)
|
|
699
803
|
if (isCliError(shown)) return JSON.stringify(shown)
|
|
700
804
|
|
|
@@ -742,7 +846,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
742
846
|
description: "List all resolved stash search paths and their status.",
|
|
743
847
|
args: {},
|
|
744
848
|
async execute() {
|
|
745
|
-
return runCli(["sources"])
|
|
849
|
+
return runCli(client as unknown as LogCapableClient, ["sources"], { toolName: "akm_sources" })
|
|
746
850
|
},
|
|
747
851
|
}),
|
|
748
852
|
akm_upgrade: tool({
|
|
@@ -755,7 +859,7 @@ export const AgentikitPlugin: Plugin = async ({ client }) => ({
|
|
|
755
859
|
const args = ["upgrade"]
|
|
756
860
|
if (check) args.push("--check")
|
|
757
861
|
if (force) args.push("--force")
|
|
758
|
-
return runCli(args)
|
|
862
|
+
return runCli(client as unknown as LogCapableClient, args, { toolName: "akm_upgrade" })
|
|
759
863
|
},
|
|
760
864
|
}),
|
|
761
865
|
},
|