@snarkipus/opencode-beads 0.9.1 → 0.9.3

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/src/plugin.ts CHANGED
@@ -1,150 +1,12 @@
1
1
  /** OpenCode adapter for the Beads issue tracker. */
2
2
 
3
- import type { Plugin, PluginInput } from "@opencode-ai/plugin";
4
- import type { Agent, Part, SessionMessagesResponse } from "@opencode-ai/sdk";
5
- import {
6
- createBeadsController,
7
- resolveProjectDirectory,
8
- type PluginRuntime,
9
- } from "./plugin-core";
10
- import { runBdPrime } from "./prime";
11
-
12
- function isRecord(value: unknown): value is Record<string, unknown> {
13
- return typeof value === "object" && value !== null;
14
- }
15
-
16
- function isSessionMessage(value: unknown): boolean {
17
- if (
18
- !isRecord(value) ||
19
- !isRecord(value.info) ||
20
- (value.info.role !== "user" && value.info.role !== "assistant") ||
21
- (value.info.agent !== undefined && typeof value.info.agent !== "string") ||
22
- (value.info.system !== undefined && typeof value.info.system !== "string") ||
23
- (value.info.model !== undefined &&
24
- (!isRecord(value.info.model) ||
25
- typeof value.info.model.providerID !== "string" ||
26
- typeof value.info.model.modelID !== "string"))
27
- ) {
28
- return false;
29
- }
30
- if (!Array.isArray(value.parts)) return false;
31
-
32
- return value.parts.every(
33
- (part) =>
34
- isRecord(part) &&
35
- typeof part.type === "string" &&
36
- (part.text === undefined || typeof part.text === "string")
37
- );
38
- }
39
-
40
- function isAgent(value: unknown): boolean {
41
- return (
42
- isRecord(value) &&
43
- typeof value.name === "string" &&
44
- (value.mode === "subagent" || value.mode === "primary" || value.mode === "all")
45
- );
46
- }
47
-
48
- /** Prevent the synthetic no-reply prompt from recursively triggering its own injection. */
49
- function isBeadsContextInjection(parts: ReadonlyArray<Part>): boolean {
50
- return parts.some(
51
- (part) =>
52
- part.type === "text" &&
53
- part.synthetic === true &&
54
- part.text.includes("<beads-context>")
55
- );
56
- }
57
-
58
- /** Adapt the official OpenCode client to the controller's small deterministic boundary. */
59
- export function createOpenCodeRuntime(client: PluginInput["client"]): PluginRuntime {
60
- return {
61
- async getMessages(projectDirectory, sessionID, limit) {
62
- const response = await client.session.messages({
63
- path: { id: sessionID },
64
- query: { directory: projectDirectory, limit },
65
- });
66
- if (response.error !== undefined) throw response.error;
67
- if (!Array.isArray(response.data) || !response.data.every(isSessionMessage)) {
68
- throw new Error("OpenCode returned malformed session messages");
69
- }
70
- return response.data satisfies SessionMessagesResponse;
71
- },
72
-
73
- async getAgents(projectDirectory) {
74
- const response = await client.app.agents({ query: { directory: projectDirectory } });
75
- if (response.error !== undefined) throw response.error;
76
- if (!Array.isArray(response.data) || !response.data.every(isAgent)) {
77
- throw new Error("OpenCode returned malformed agents");
78
- }
79
- return response.data satisfies Agent[];
80
- },
81
-
82
- async prompt(projectDirectory, sessionID, body) {
83
- const response = await client.session.prompt({
84
- path: { id: sessionID },
85
- query: { directory: projectDirectory },
86
- body,
87
- });
88
- if (response.error !== undefined) throw response.error;
89
- if (response.data === undefined) throw new Error("OpenCode returned no prompt result");
90
- },
91
-
92
- async prime(projectDirectory) {
93
- return runBdPrime(projectDirectory);
94
- },
95
-
96
- async diagnose(diagnostic) {
97
- const extra =
98
- diagnostic.code === "config_collision"
99
- ? { surface: diagnostic.surface, names: diagnostic.names }
100
- : { sessionID: diagnostic.sessionID };
101
- const response = await client.app.log({
102
- query: { directory: diagnostic.directory },
103
- body: {
104
- service: "opencode-beads",
105
- level: "warn",
106
- message: diagnostic.code,
107
- extra,
108
- },
109
- });
110
- if (response.error !== undefined) throw response.error;
111
- if (response.data === undefined) throw new Error("OpenCode returned no log result");
112
- },
113
- };
114
- }
3
+ import type { Plugin } from "@opencode-ai/plugin";
4
+ import { resolveProjectDirectory } from "./plugin-core";
5
+ import { createBeadsHooks } from "./plugin-hooks";
6
+ import { createOpenCodeRuntime } from "./opencode-runtime";
115
7
 
116
8
  export const BeadsPlugin: Plugin = async ({ client, directory, worktree }) => {
117
9
  const projectDirectory = resolveProjectDirectory(directory, worktree);
118
10
  const runtime = createOpenCodeRuntime(client);
119
-
120
- const controller = await createBeadsController(runtime, projectDirectory);
121
-
122
- return {
123
- "chat.message": async (input, output) => {
124
- if (isBeadsContextInjection(output.parts)) return;
125
-
126
- await controller.onMessage(
127
- {
128
- sessionID: input.sessionID,
129
- model: input.model,
130
- agent: input.agent,
131
- },
132
- (context) => {
133
- output.message.system = output.message.system
134
- ? `${output.message.system}\n\n${context}`
135
- : context;
136
- }
137
- );
138
- },
139
-
140
- event: async ({ event }) => {
141
- if (event.type === "session.compacted") {
142
- await controller.onCompacted(event.properties.sessionID);
143
- }
144
- },
145
-
146
- config: async (config) => {
147
- await controller.configure(config);
148
- },
149
- };
11
+ return createBeadsHooks(runtime, projectDirectory);
150
12
  };
package/src/prime.ts CHANGED
@@ -1,4 +1,7 @@
1
+ import { kill as killProcess } from "node:process";
2
+
1
3
  export const DEFAULT_PRIME_TIMEOUT_MS = 10_000;
4
+ export const DEFAULT_PRIME_DRAIN_TIMEOUT_MS = 1_000;
2
5
 
3
6
  export class PrimeTimeoutError extends Error {
4
7
  constructor(timeoutMs: number) {
@@ -15,25 +18,55 @@ export class PrimeProcessError extends Error {
15
18
  }
16
19
 
17
20
  export interface PrimeProcess {
21
+ pid: number;
18
22
  stdout: ReadableStream<Uint8Array>;
19
23
  stderr: ReadableStream<Uint8Array>;
20
24
  exited: Promise<number>;
21
25
  kill(signal?: NodeJS.Signals): void;
26
+ killTree?(signal?: NodeJS.Signals): void;
22
27
  }
23
28
 
24
29
  export interface PrimeExecutionOptions {
25
30
  timeoutMs?: number;
31
+ drainTimeoutMs?: number;
26
32
  spawn?: (directory: string, args: readonly string[]) => PrimeProcess;
27
33
  scheduleTimeout?: (callback: () => void, delayMs: number) => () => void;
34
+ scheduleDrainTimeout?: (callback: () => void, delayMs: number) => () => void;
28
35
  }
29
36
 
30
37
  function spawnPrime(directory: string, args: readonly string[]): PrimeProcess {
31
- return Bun.spawn(["bd", "prime", ...args], {
38
+ const child = Bun.spawn(["bd", "prime", ...args], {
32
39
  cwd: directory,
33
40
  stdin: "ignore",
34
41
  stdout: "pipe",
35
42
  stderr: "pipe",
43
+ detached: true,
36
44
  });
45
+ let processGroupID: number | undefined;
46
+ if (process.platform !== "win32") {
47
+ const group = Bun.spawnSync(["ps", "-o", "pgid=", "-p", String(child.pid)], {
48
+ stdout: "pipe",
49
+ stderr: "ignore",
50
+ timeout: 100,
51
+ });
52
+ const parsed = Number.parseInt(new TextDecoder().decode(group.stdout).trim(), 10);
53
+ if (group.exitCode === 0 && parsed === child.pid && parsed > 1) processGroupID = parsed;
54
+ }
55
+
56
+ return {
57
+ pid: child.pid,
58
+ stdout: child.stdout,
59
+ stderr: child.stderr,
60
+ exited: child.exited,
61
+ kill: (signal) => child.kill(signal),
62
+ killTree: (signal) => {
63
+ if (processGroupID !== undefined) {
64
+ killProcess(-processGroupID, signal);
65
+ } else {
66
+ child.kill(signal);
67
+ }
68
+ },
69
+ };
37
70
  }
38
71
 
39
72
  function scheduleTimeout(callback: () => void, delayMs: number): () => void {
@@ -41,15 +74,42 @@ function scheduleTimeout(callback: () => void, delayMs: number): () => void {
41
74
  return () => clearTimeout(timer);
42
75
  }
43
76
 
77
+ function terminateProcessTree(child: PrimeProcess): void {
78
+ try {
79
+ (child.killTree ?? child.kill)("SIGKILL");
80
+ } catch {
81
+ try {
82
+ child.kill("SIGKILL");
83
+ } catch {
84
+ // Timeout remains authoritative if the process exited concurrently.
85
+ }
86
+ }
87
+ }
88
+
89
+ async function drainAfterKill(
90
+ completion: Promise<unknown>,
91
+ timeoutMs: number,
92
+ scheduler: (callback: () => void, delayMs: number) => () => void
93
+ ): Promise<void> {
94
+ await new Promise<void>((resolve) => {
95
+ const cancelTimeout = scheduler(resolve, timeoutMs);
96
+ void completion.finally(() => {
97
+ cancelTimeout();
98
+ resolve();
99
+ });
100
+ });
101
+ }
102
+
44
103
  async function runPrimeAttempt(
45
104
  directory: string,
46
105
  args: readonly string[],
47
106
  options: PrimeExecutionOptions = {}
48
107
  ): Promise<string> {
49
108
  const timeoutMs = options.timeoutMs ?? DEFAULT_PRIME_TIMEOUT_MS;
50
- const process = (options.spawn ?? spawnPrime)(directory, args);
51
- const stdout = new Response(process.stdout).text();
52
- const stderr = new Response(process.stderr).text();
109
+ const drainTimeoutMs = options.drainTimeoutMs ?? DEFAULT_PRIME_DRAIN_TIMEOUT_MS;
110
+ const child = (options.spawn ?? spawnPrime)(directory, args);
111
+ const stdout = new Response(child.stdout).text();
112
+ const stderr = new Response(child.stderr).text();
53
113
 
54
114
  let timedOut = false;
55
115
  let rejectTimeout: (error: PrimeTimeoutError) => void = () => {};
@@ -58,11 +118,11 @@ async function runPrimeAttempt(
58
118
  });
59
119
  const cancelTimeout = (options.scheduleTimeout ?? scheduleTimeout)(() => {
60
120
  timedOut = true;
61
- process.kill("SIGKILL");
121
+ terminateProcessTree(child);
62
122
  rejectTimeout(new PrimeTimeoutError(timeoutMs));
63
123
  }, timeoutMs);
64
124
 
65
- const completion = Promise.all([process.exited, stdout, stderr]).then(
125
+ const completion = Promise.all([child.exited, stdout, stderr]).then(
66
126
  ([exitCode, output, errorOutput]) => {
67
127
  if (exitCode !== 0) throw new PrimeProcessError(exitCode, errorOutput);
68
128
  return output;
@@ -74,7 +134,11 @@ async function runPrimeAttempt(
74
134
  } finally {
75
135
  cancelTimeout();
76
136
  if (timedOut) {
77
- await completion.catch(() => undefined);
137
+ await drainAfterKill(
138
+ completion.catch(() => undefined),
139
+ drainTimeoutMs,
140
+ options.scheduleDrainTimeout ?? scheduleTimeout
141
+ );
78
142
  }
79
143
  }
80
144
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Log and label agent interactions (append-only JSONL)
3
- argument-hint: record|label
3
+ argument-hint: "record|label"
4
4
  ---
5
5
 
6
6
  Append-only audit logging for agent interactions (prompts, responses, tool calls) in `.beads/interactions.jsonl`.
@@ -25,4 +25,3 @@ Each line is one event. Labeling is done by appending a new `"label"` event refe
25
25
  - Audit entries are **append-only** (no in-place edits).
26
26
  - `bd dolt push` includes `.beads/interactions.jsonl` in the commit allowlist.
27
27
 
28
-
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Show blocked issues
3
- argument-hint: []
3
+ argument-hint: ""
4
4
  ---
5
5
 
6
6
  Show all issues that are blocked by dependencies.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Close a completed issue
3
- argument-hint: [issue-id] [reason]
3
+ argument-hint: "[issue-id] [reason]"
4
4
  ---
5
5
 
6
6
  Close a beads issue that's been completed.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: View or manage comments on an issue
3
- argument-hint: [issue-id]
3
+ argument-hint: "[issue-id]"
4
4
  ---
5
5
 
6
6
  View or add comments to a beads issue.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Compact old closed issues using semantic summarization
3
- argument-hint: [--all] [--id issue-id] [--dry-run]
3
+ argument-hint: "[--all] [--id issue-id] [--dry-run]"
4
4
  ---
5
5
 
6
6
  Reduce database size by summarizing closed issues no longer actively referenced.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Create a new issue interactively
3
- argument-hint: [title] [type] [priority]
3
+ argument-hint: "[title] [type] [priority]"
4
4
  ---
5
5
 
6
6
  Create a new beads issue. If arguments are provided:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Record, list, and manage project decisions with rationale tracking
3
- argument-hint: record|list|show|supersede
3
+ argument-hint: "record|list|show|supersede"
4
4
  ---
5
5
 
6
6
  Record and track project decisions as beads issues with structured rationale, alternatives considered, and links to affected work.
@@ -9,7 +9,7 @@ Decisions use `--type decision`. The description field holds the structured deci
9
9
 
10
10
  ## Record a Decision
11
11
 
12
- When the user wants to record a decision (or you invoke `bd decision record`):
12
+ When the user wants to record a decision (i.e. the `record` action of this command):
13
13
 
14
14
  1. Gather the following (ask if not provided):
15
15
  - **Title**: Short summary of what was decided (required)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Delete issues and clean up references
3
- argument-hint: [issue-ids...] [--force]
3
+ argument-hint: "[issue-ids...] [--force]"
4
4
  ---
5
5
 
6
6
  Delete one or more issues and clean up all references.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Manage dependencies between issues
3
- argument-hint: [command] [from-id] [to-id]
3
+ argument-hint: "[command] [from-id] [to-id]"
4
4
  ---
5
5
 
6
6
  Manage dependencies between beads issues.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Epic management commands
3
- argument-hint: [command]
3
+ argument-hint: "[command]"
4
4
  ---
5
5
 
6
6
  Manage epics (large features composed of multiple issues).
@@ -21,6 +21,9 @@ Manage epics (large features composed of multiple issues).
21
21
  1. Create epic: `bd create "Large Feature" -t epic -p 1`
22
22
  2. Link subtasks: `bd dep add bd-20 bd-10 --type parent-child` (task bd-20 is child of epic bd-10)
23
23
  - Or at creation: `bd create "Subtask title" -t task --parent bd-10`
24
+ - Children inherit parent labels by default. If the epic uses size/effort
25
+ labels and children should have their own, add `--no-inherit-labels`
26
+ (GH#4562).
24
27
  3. Track progress: `bd epic status`
25
28
  4. Auto-close when done: `bd epic close-eligible`
26
29
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Export issues to JSONL format
3
- argument-hint: [-o output-file]
3
+ argument-hint: "[-o output-file]"
4
4
  ---
5
5
 
6
6
  Export all issues to JSON Lines format (one JSON object per line).
@@ -9,7 +9,7 @@ Export all issues to JSON Lines format (one JSON object per line).
9
9
 
10
10
  - **To stdout**: `bd export`
11
11
  - **To file**: `bd export -o issues.jsonl`
12
- - **Filter by status**: `bd export --status open`
12
+ - **Include all records**: `bd export --all -o full.jsonl`
13
13
 
14
14
  Issues are sorted by ID for consistent diffs, making git diffs readable.
15
15
 
@@ -1,18 +1,84 @@
1
1
  ---
2
- description: Import issues from JSONL format (removed)
3
- argument-hint: (removed)
2
+ description: Import issues and memories from JSONL
3
+ argument-hint: "[file|-] [--input file] [--dry-run] [--dedup] [--allow-stale]"
4
4
  ---
5
5
 
6
- `bd import` has been **removed**.
6
+ `bd import` imports newline-delimited JSON into an existing Beads database.
7
+ Issues with new IDs are created and existing IDs use guarded upsert semantics.
8
+ The command is not supported in proxied-server mode.
7
9
 
8
- ## Migration
9
-
10
- If you need to import issues from a JSONL file, use `bd init` with the `--from-jsonl` flag:
10
+ ## Usage
11
11
 
12
12
  ```bash
13
- bd init <prefix> --from-jsonl issues.jsonl
13
+ bd import # Read .beads/<import.path>
14
+ bd import backup.jsonl # Read a specific file
15
+ bd import --input backup.jsonl # Same as -i backup.jsonl
16
+ bd import - # Read JSONL from stdin
17
+ bd export --include-memories | bd import - # Round-trip issues and memories
18
+ bd import --dry-run backup.jsonl # Parse and report without writing
19
+ bd import --json backup.jsonl # Return a structured result
14
20
  ```
15
21
 
16
- ## Note
22
+ With no file argument, the source is the `import.path` file under `.beads/`;
23
+ `import.path` defaults to `issues.jsonl`. Use either a positional file or
24
+ `--input`/`-i`, not both. The special path `-` reads stdin. With `--global` and
25
+ no file, the source is `global-issues.jsonl` in the active Beads directory.
26
+
27
+ Each non-empty line must be a JSON object. Issue records accept the schema
28
+ emitted by `bd export`; `title` is the only required issue field. Records with
29
+ `"_type":"memory"` and non-empty `key` and `value` fields are imported as
30
+ persistent memories. Optional export header records are ignored, and tombstone
31
+ rows are skipped. `bd export` omits memories by default; add
32
+ `--include-memories` or `--all` when they should be carried into an import.
33
+
34
+ ## Merge and Safety Semantics
35
+
36
+ For records that supply `updated_at`, an incoming row rewrites an existing
37
+ issue only when its timestamp is strictly newer. Older records are skipped
38
+ wholesale, including their labels, comments, and dependencies. When timestamps
39
+ are equal, the local issue row wins, while those auxiliary records still merge.
40
+ The stale check is repeated inside the upsert so a concurrent newer local update
41
+ is not overwritten.
42
+
43
+ If `updated_at` is omitted, the importer fills it with the current time during
44
+ the write. A record naming an existing ID can therefore overwrite local state;
45
+ include the exported timestamp when stale protection matters.
46
+
47
+ Use `--allow-stale` only when deliberately restoring an older snapshot: it
48
+ disables that guard and can overwrite newer local issue state. Imports are
49
+ upserts, and labels, comments, and dependencies are deduplicated. Re-running
50
+ canonical export data or other input with stable issue IDs and preserved
51
+ `updated_at` values is safe and converges. Without a preserved timestamp, each
52
+ run can appear newer and rewrite the row. An issue record without an ID is
53
+ assigned one; re-importing it can create another issue instead of targeting the
54
+ first.
55
+
56
+ Large issue imports use bounded SQL transaction chunks. If one fails, the
57
+ command exits nonzero and keeps the already committed prefix in the Dolt working
58
+ set; no final import-summary Dolt commit is created. Re-run stable-ID input to
59
+ resume only when its `updated_at` values are also preserved.
60
+
61
+ After a successful non-dry import with accepted issue or memory records, the
62
+ command calls `store.Commit` with an import summary regardless of the
63
+ `dolt.auto-commit` policy. That commit can include unrelated pending working-set
64
+ changes; in direct server mode, config (including memories) is excluded from
65
+ this commit. When commit isolation matters, run `bd doctor` before importing and
66
+ proceed only when its Dolt Status check reports a clean working set.
67
+
68
+ The database must already exist; initialize or bootstrap it before importing.
69
+ Use `--dry-run` to parse the input, apply optional title deduplication, and
70
+ report issue and memory counts without writing. It does not run write-time field
71
+ validation or predict stale skips and updates.
72
+
73
+ ## Flags
17
74
 
18
- Dolt is the primary storage backend. Manual JSONL import is no longer supported as a standalone command.
75
+ - `--input`, `-i <file>`: read a specific file instead of a positional path.
76
+ - `--dry-run`: report parsed record counts without writing.
77
+ - `--dedup`: skip an input issue whose title exactly matches, ignoring case, an
78
+ existing non-closed issue. Input rows are not compared with one another; if
79
+ the existing-issue search fails, title filtering is skipped.
80
+ - `--allow-stale`: import older rows too, allowing newer local state to be
81
+ overwritten.
82
+ - `--json`: use global JSON-output mode for structured counts and IDs. The
83
+ `created` count is accepted issue rows, including existing rows, not only new
84
+ inserts.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Initialize beads in the current project
3
- argument-hint: [prefix]
3
+ argument-hint: "[prefix]"
4
4
  ---
5
5
 
6
6
  Initialize beads issue tracking in the current directory.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Manage issue labels
3
- argument-hint: [command] [issue-id] [label]
3
+ argument-hint: "[command] [issue-id] [label]"
4
4
  ---
5
5
 
6
6
  Manage labels on beads issues. Labels provide flexible cross-cutting metadata beyond structured fields (status, priority, type).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: List issues with optional filters
3
- argument-hint: [--status] [--priority] [--type] [--assignee] [--label]
3
+ argument-hint: "[--status] [--priority] [--type] [--assignee] [--label]"
4
4
  ---
5
5
 
6
6
  List beads issues with optional filtering.
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  description: Quick start guide for bd workflows (deprecated)
3
- argument-hint: []
3
+ argument-hint: ""
4
4
  ---
5
5
 
6
- **Note:** The `bd quickstart` command is deprecated. See the [Quick Start](https://gastownhall.github.io/beads/getting-started/quickstart) on the documentation site, or the repo pointer [docs/QUICKSTART.md](../docs/QUICKSTART.md).
6
+ **Note:** The `bd quickstart` command is deprecated. See the [Quick Start](https://beads.gascity.com/getting-started/quickstart) on the documentation site, or the in-repo source [docs/getting-started/quickstart.md](https://github.com/gastownhall/beads/blob/main/docs/getting-started/quickstart.md).
7
7
 
8
8
  The quickstart documentation covers:
9
9
  - Getting started with bd
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Rename the issue prefix for all issues
3
- argument-hint: <new-prefix> [--dry-run]
3
+ argument-hint: "<new-prefix> [--dry-run]"
4
4
  ---
5
5
 
6
6
  Rename the issue prefix for all issues in the database.
@@ -9,7 +9,6 @@ Updates all issue IDs and all text references across all fields.
9
9
 
10
10
  ## Prefix Rules
11
11
 
12
- - Max length: 8 characters
13
12
  - Allowed: lowercase letters, numbers, hyphens
14
13
  - Must start with a letter
15
14
  - Must end with a hyphen (e.g., 'kw-', 'work-')
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Reopen closed issues
3
- argument-hint: [issue-ids...] [--reason]
3
+ argument-hint: "[issue-ids...] [--reason]"
4
4
  ---
5
5
 
6
6
  Reopen one or more closed issues.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Restore full history of compacted issue from git
3
- argument-hint: <issue-id>
3
+ argument-hint: "<issue-id>"
4
4
  ---
5
5
 
6
6
  Restore full history of a compacted issue from git version control.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Search issues by text query
3
- argument-hint: <query> [--status] [--label] [--assignee]
3
+ argument-hint: "<query> [--status] [--label] [--assignee]"
4
4
  ---
5
5
 
6
6
  Search issues across title, description, and ID with a simple text query.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Show detailed information about an issue
3
- argument-hint: [issue-id]
3
+ argument-hint: "[issue-id]"
4
4
  ---
5
5
 
6
6
  Display detailed information about a beads issue.