akm-opencode 0.0.18 → 0.0.19

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.ts +127 -23
  3. 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") return JSON.stringify(command)
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
- return execFileSync(command, [...args, "--format", "json"], {
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(input: { ref?: string; query?: string }, type: AssetType): { ok: true; ref: string } | CliError {
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 resolved = resolveRefInput({ ref, query }, "agent")
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 resolved = resolveRefInput({ ref, query }, "command")
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
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-opencode",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Agentikit - search and show extension assets via the akm CLI.",
6
6
  "keywords": [