akm-opencode 0.9.2202608290901 → 0.9.7202608312104

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # akm-opencode
2
2
 
3
- OpenCode plugin for [AKM](https://github.com/itlackey/akm) `^0.9.2`. It exposes exactly five public tools and uses lifecycle hooks to bring relevant AKM context into a session.
3
+ OpenCode plugin for [AKM](https://github.com/itlackey/akm) `^0.9.7`. It exposes exactly five public tools and uses lifecycle hooks to bring relevant AKM context into a session.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,13 +18,13 @@ Add the plugin to `opencode.json`:
18
18
  | --- | --- |
19
19
  | `akm_search` | Search configured bundles or registries. `source` accepts `local`, `registry`, `all`, or a configured bundle name. |
20
20
  | `akm_show` | Show a concept by `[bundle//]conceptId[#fragment]`. A fragment selects a Markdown section. |
21
- | `akm_curate` | Return ranked concepts for a task or topic. |
21
+ | `akm_curate` | Return ranked concepts for a task or topic. Optional `pack` is a token budget that returns the selected local assets' full content in one response; registry hits are omitted from packed items. |
22
22
  | `akm_feedback` | Record positive or negative feedback for a concept. |
23
23
  | `akm_remember` | Save durable knowledge as a searchable memory. |
24
24
 
25
25
  `akm_search`, `akm_show`, and `akm_curate` call the bundled AKM read APIs in process. `akm_feedback` and `akm_remember` use the compatible AKM CLI because they mutate AKM state. Failures return structured results and are logged through OpenCode app logging.
26
26
 
27
- Use the `ref` returned by search or curate directly with show or feedback. Concept IDs look like `skills/code-review`, `memories/release-retro`, or `team-playbook//knowledge/deploy#Rollback`.
27
+ Use the `ref` returned by search or curate directly with show or feedback. When `akm_curate.pack` is set, the response already includes packed local content, so a separate show call is only needed for omitted or registry-only hits. Concept IDs look like `skills/code-review`, `memories/release-retro`, or `team-playbook//knowledge/deploy#Rollback`.
28
28
 
29
29
  ## Lifecycle Hooks
30
30
 
@@ -113,7 +113,7 @@ These three are read once, when the plugin module is imported, so they must be s
113
113
 
114
114
  ## Usage
115
115
 
116
- 1. Start with `akm_curate` for task-oriented discovery.
116
+ 1. Start with `akm_curate` for task-oriented discovery; set `pack` when you want the selected local content immediately.
117
117
  2. Use `akm_search` when you know the concept name and need its exact ID.
118
118
  3. Fetch the full concept with `akm_show` before relying on it.
119
119
  4. Record the outcome with `akm_feedback`.
package/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type Plugin, tool } from "@opencode-ai/plugin"
2
2
  // @ts-expect-error akm-cli does not publish declarations for this in-process entrypoint.
3
- import { akmCurate } from "akm-cli/dist/commands/read/curate.js"
3
+ import { akmCurate, packCuratedHits } from "akm-cli/dist/commands/read/curate.js"
4
4
  // @ts-expect-error akm-cli does not publish declarations for this in-process entrypoint.
5
5
  import { akmSearch } from "akm-cli/dist/commands/read/search.js"
6
6
  // @ts-expect-error akm-cli does not publish declarations for this in-process entrypoint.
@@ -48,7 +48,7 @@ const AKM_REQUIRED_VERSION_RANGE = AKM_VERSION_RANGE
48
48
  // The consent banner's package specification is kept explicit so it remains a
49
49
  // valid npm install target even if the shared compatibility range later grows
50
50
  // extra clauses. Keep it in sync with the minimum supported stable release.
51
- const AKM_RECOMMENDED_INSTALL_REF = "akm-cli@^0.9.2"
51
+ const AKM_RECOMMENDED_INSTALL_REF = "akm-cli@^0.9.7"
52
52
 
53
53
  const AKM_AUTO_FEEDBACK = (process.env.AKM_AUTO_FEEDBACK ?? "1") !== "0"
54
54
  const AKM_AUTO_CURATE = (process.env.AKM_AUTO_CURATE ?? "1") !== "0"
@@ -194,7 +194,7 @@ const akmVersionProbeCache = new Map<string, string | null>()
194
194
  // whitespace-token extractor and is the single source of truth here.
195
195
  const PROPOSED_QUALITY_WARNING = "Do not treat proposed assets as curated until accepted."
196
196
  const AKM_WORKFLOW_INSTRUCTION = [
197
- "# AKM workflow (v0.9.2)",
197
+ "# AKM workflow (v0.9.7)",
198
198
  "",
199
199
  "Use AKM as a reusable knowledge and workflow bundle.",
200
200
  "",
@@ -820,7 +820,7 @@ async function getPendingProposalCount(client: LogCapableClient, sessionID?: str
820
820
  const command = resolveAkmCommand()
821
821
  if (typeof command === "object" && "ok" in command) return { count: 0, unsupported: true }
822
822
  try {
823
- // AKM 0.9.2 canonical proposal-queue listing path: `akm proposal list`.
823
+ // AKM 0.9.7 canonical proposal-queue listing path: `akm proposal list`.
824
824
  const stdout = execResolvedAkm(command, ["proposal", "list", "--status", "pending", "--format", "json"], {
825
825
  encoding: "utf8",
826
826
  timeout: AKM_PENDING_PROPOSAL_TIMEOUT_MS,
@@ -2662,11 +2662,24 @@ async function runInProcess(
2662
2662
  meta: CliLogMeta,
2663
2663
  ): Promise<string> {
2664
2664
  try {
2665
+ if (
2666
+ operation === "curate"
2667
+ && input.pack !== undefined
2668
+ && (typeof input.pack !== "number" || !Number.isInteger(input.pack) || input.pack <= 0)
2669
+ ) {
2670
+ throw new Error("pack must be a positive integer token budget")
2671
+ }
2665
2672
  const result = operation === "search"
2666
2673
  ? await akmSearch(input as Parameters<typeof akmSearch>[0])
2667
2674
  : operation === "show"
2668
2675
  ? await akmShowUnified(input as Parameters<typeof akmShowUnified>[0])
2669
- : await akmCurate(input as Parameters<typeof akmCurate>[0])
2676
+ : await (async () => {
2677
+ const { pack, ...curateInput } = input
2678
+ const curated = await akmCurate(curateInput as Parameters<typeof akmCurate>[0])
2679
+ return typeof pack === "number"
2680
+ ? packCuratedHits(curated, pack)
2681
+ : curated
2682
+ })()
2670
2683
  const output = JSON.stringify(result)
2671
2684
  const refs = extractAkmRefsFromString(output)
2672
2685
  noteRecentRefs(meta.sessionID, refs)
@@ -2749,6 +2762,7 @@ type SearchHit = {
2749
2762
  description?: string
2750
2763
  score?: number
2751
2764
  whyMatched?: string[]
2765
+ matchStage?: "exact" | "prefix" | "relaxed"
2752
2766
  run?: string
2753
2767
  origin?: string | null
2754
2768
  size?: string
@@ -3579,18 +3593,19 @@ const akmPlugin: Plugin = async ({ client, worktree, directory }) => {
3579
3593
  // zero akm_* calls while curation was demonstrably available (#95).
3580
3594
  // Leading with the decision — when to reach for this instead of just
3581
3595
  // reading the file — is what it has to win on.
3582
- description: "Reach for this BEFORE writing or editing a config file, manifest, schema, or command for any tool, format, or API whose exact syntax or keys you are not certain of — including a file already present in the workspace, since having read a file does not mean you know its schema. PRIMARY discovery entry point for the bundle: describe the task in natural language and this returns the top matches as a ranked list. Pass a hit's ref to akm_show before relying on it, then record akm_feedback once the result is known.",
3596
+ description: "Reach for this BEFORE writing or editing a config file, manifest, schema, or command for any tool, format, or API whose exact syntax or keys you are not certain of — including a file already present in the workspace, since having read a file does not mean you know its schema. PRIMARY discovery entry point for the bundle: describe the task in natural language and this returns the top matches as a ranked list. Set pack to a token budget when you need the selected local assets' full content in one response; otherwise pass a hit's ref to akm_show before relying on it. Record akm_feedback once the result is known.",
3583
3597
  args: {
3584
3598
  query: tool.schema.string().describe("Task, topic, or natural-language description of what you want to do."),
3585
3599
  type: tool.schema.enum(ASSET_TYPES as unknown as [string, ...string[]]).optional().describe("Optional asset type filter."),
3586
3600
  limit: tool.schema.number().optional().describe("Maximum number of curated matches to return. Defaults to 4."),
3587
3601
  source: tool.schema.string().optional().describe("Search source: 'local', 'registry', 'all', or a configured bundle name."),
3602
+ pack: tool.schema.number().optional().describe("Optional positive token budget for packing ranked local assets' full content into this response. Registry hits are never packed."),
3588
3603
  },
3589
- async execute({ query, type, limit, source }, context) {
3604
+ async execute({ query, type, limit, source, pack }, context) {
3590
3605
  return runInProcess(
3591
3606
  client as unknown as LogCapableClient,
3592
3607
  "curate",
3593
- { query, type: type === "any" ? undefined : type, limit, source },
3608
+ { query, type: type === "any" ? undefined : type, limit, source, pack },
3594
3609
  { toolName: "akm_curate", sessionID: context.sessionID, directory: context.directory },
3595
3610
  )
3596
3611
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-opencode",
3
- "version": "0.9.2202608290901",
3
+ "version": "0.9.7202608312104",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for AKM 0.9 with in-process search, show, and curate tools plus feedback and remember.",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@opencode-ai/plugin": "^1.18.14",
42
- "akm-cli": "^0.9.2"
42
+ "akm-cli": "^0.9.7"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^26.1.1",
@@ -13,16 +13,17 @@
13
13
  // same code path runs on both sides.
14
14
  //
15
15
  // A single caret clause anchored at the stable release covers the whole
16
- // supported line: `^0.9.2` admits stable 0.9.2 and later 0.9.x releases.
17
- // 0.9.2 is the compatibility floor: its ref grammar, workflow lifecycle and
18
- // task/workflow wire contracts are the ones these plugins implement.
16
+ // supported line: `^0.9.7` admits stable 0.9.7 and later 0.9.x releases.
17
+ // 0.9.7 is the compatibility floor: its ref grammar, progressive-search
18
+ // metadata, token-budgeted curate packing, workflow lifecycle, and task/workflow
19
+ // wire contracts are the ones these plugins implement.
19
20
  //
20
- // KNOWN GAP: NO prerelease satisfies this range — not 0.9.2-rc.1, and not a
21
- // *future* line such as 0.9.3-rc.1. That is node-semver's documented behavior
21
+ // KNOWN GAP: NO prerelease satisfies this range — not 0.9.7-rc.1, and not a
22
+ // *future* line such as 0.9.8-rc.1. That is node-semver's documented behavior
22
23
  // and the vendored matcher reproduces it: a prerelease only satisfies a range
23
24
  // whose lower bound is a prerelease with the same major.minor.patch. Admitting
24
25
  // a prerelease line again is an explicit one-clause edit here
25
- // (`^0.9.2 || ^0.9.3-rc.1`) when such a build actually needs testing — a
26
+ // (`^0.9.7 || ^0.9.8-rc.1`) when such a build actually needs testing — a
26
27
  // deliberate opt-in rather than a range that silently accepts untested
27
28
  // prereleases.
28
29
  //
@@ -32,7 +33,7 @@
32
33
 
33
34
  import { satisfies } from "./vendor-semver"
34
35
 
35
- export const AKM_VERSION_RANGE = "^0.9.2"
36
+ export const AKM_VERSION_RANGE = "^0.9.7"
36
37
 
37
38
  /**
38
39
  * True when `version` is a valid semver string that satisfies
@@ -36,7 +36,7 @@ export function shouldRecall(prompt: string, options?: { activeWorkflow?: boolea
36
36
  return { shouldRecall: false, reason: "skip-chitchat", query: text, scopeHints }
37
37
  }
38
38
  // Reuse the resolver-facing parser rather than carrying a second, stale
39
- // grammar here. AKM 0.9.2 refs are [bundle//]conceptId[#fragment]; retired
39
+ // grammar here. AKM 0.9.7 refs are [bundle//]conceptId[#fragment]; retired
40
40
  // type:name strings must not turn an otherwise low-signal prompt into an
41
41
  // explicit AKM recall.
42
42
  if (/\bakm\b|\bbundle\b/.test(lower) || extractAkmRefsFromString(text).length > 0) {