@bike4mind/cli 0.15.3 → 0.17.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 CHANGED
@@ -578,6 +578,55 @@ Coming soon:
578
578
  ⏳ Session search and management
579
579
  ⏳ Tool execution monitoring
580
580
 
581
+ ## Running as a `claude` engine inside a host app
582
+
583
+ The CLI can be driven by a host app (e.g. a kanban-style agent pipeline) as a
584
+ drop-in replacement for `claude` — running a pipeline **stage** or a **board AI /
585
+ YAML** pane with full parity (board tools over HTTP MCP, the 3-layer brief
586
+ injected, the spec auto-fired on turn 1, and the live-card `processing` /
587
+ `action_required` / `ready` signal).
588
+
589
+ A host that only launches an engine whose executable basename is exactly `claude`
590
+ can be pointed at a **symlink** named `claude`:
591
+
592
+ ```bash
593
+ # Create a claude-named symlink to the CLI entry point somewhere on disk:
594
+ ln -s "$(pwd)/apps/cli/bin/bike4mind-cli.mjs" /usr/local/bin/claude-b4m/claude
595
+
596
+ # In the host, set the engine's `terminal_command` to that symlink path:
597
+ # /usr/local/bin/claude-b4m/claude
598
+ ```
599
+
600
+ Use a **direct symlink** whose basename is `claude` — not a `package.json` bin
601
+ alias (it would shadow the real `claude`) and not a wrapper shell script (argv
602
+ gets mangled). No other setup is required; the CLI replicates claude's launch-flag
603
+ and lifecycle-hook contract.
604
+
605
+ ### Supported claude-compatible flags
606
+
607
+ These are parsed in `bin/bike4mind-cli.mjs` into `B4M_*` env vars consumed by the
608
+ runtime. Unknown flags are tolerated (never hard-error) and the interactive TUI is
609
+ preserved (a positional prompt seeds **and** submits turn 1 without switching to
610
+ headless `-p`):
611
+
612
+ | Flag | Effect |
613
+ | --- | --- |
614
+ | `--mcp-config <file>` | Inject MCP servers from a claude-shape JSON (`{ "mcpServers": {...} }`). Supports HTTP transport (`type: "http"`, `url`, `headers`) with per-launch Bearer auth. |
615
+ | `--strict-mcp-config` | Use ONLY `--mcp-config` servers; ignore file-config and `.mcp.json` (board YAML pane). |
616
+ | `--append-system-prompt <text>` | Append text verbatim to the end of the system prompt (the 3-layer brief). |
617
+ | `--allowedTools <patterns>` | Auto-approve matching tools without a permission prompt (glob `mcp__manifold__*` or a space-separated explicit list). |
618
+ | `--settings <json>` | Inline JSON; the `hooks` subset drives lifecycle hooks (see below). Malformed JSON is ignored, never fatal. |
619
+ | `--session-id <uuid>` / `--resume <uuid>` | Pin / resume a session (board pane). `/clear` and `/compact` keep the pinned uuid; a bad `--resume` prints `No conversation found with session ID <uuid>` and exits non-zero so the host can self-heal the pane. |
620
+ | `<positional prompt>` | Seeds and auto-fires turn 1 while staying interactive. |
621
+
622
+ ### Lifecycle hooks (`--settings.hooks`)
623
+
624
+ Mirrors claude's hook contract for the host's `action_required` signal: a
625
+ `Notification`/`permission_prompt` command writes a sentinel file while an
626
+ interactive permission prompt blocks; `PostToolUse` / `Stop` / `UserPromptSubmit`
627
+ commands remove it. Each hook command runs via a real shell with its stdin piped
628
+ then closed (EOF), so a blocking `cat > <file>` hook returns immediately.
629
+
581
630
  ## License
582
631
 
583
632
  Private - Bike4Mind
@@ -111,10 +111,48 @@ const argv = await yargs(hideBin(process.argv))
111
111
  type: 'string',
112
112
  description: 'Add local Ollama models to the model picker (e.g. http://localhost:11434)',
113
113
  })
114
+ // ─── claude-compatible flags (host drop-in masquerade) ──────────────────────
115
+ // Declared so a host's claude launch flags parse into named options instead of
116
+ // leaking into the positional `argv._` task. See apps/cli README "host app".
117
+ .option('mcp-config', {
118
+ type: 'string',
119
+ description: 'Path to a JSON file of MCP servers to inject ({ "mcpServers": {...} })',
120
+ })
121
+ .option('strict-mcp-config', {
122
+ type: 'boolean',
123
+ description: 'Use ONLY --mcp-config servers; ignore file-config and .mcp.json',
124
+ default: false,
125
+ })
126
+ .option('append-system-prompt', {
127
+ type: 'string',
128
+ description: 'Text appended verbatim to the end of the composed system prompt',
129
+ })
130
+ .option('allowedTools', {
131
+ type: 'array',
132
+ string: true,
133
+ description: 'Tool names/globs auto-approved without a permission prompt (e.g. mcp__manifold__*)',
134
+ })
135
+ .option('settings', {
136
+ type: 'string',
137
+ description: 'Inline JSON settings (currently: lifecycle hooks) merged over user config',
138
+ })
139
+ .option('session-id', {
140
+ type: 'string',
141
+ description: 'Pin this session to a fixed uuid (first launch of a resumable pane)',
142
+ })
143
+ .option('resume', {
144
+ type: 'string',
145
+ description: 'Resume an existing session by uuid',
146
+ })
114
147
  .option('api-url', {
115
148
  type: 'string',
116
149
  description: 'Set a custom API URL (self-hosted instance) and clear auth tokens, then exit',
117
150
  })
151
+ .option('no-remote-skills', {
152
+ type: 'boolean',
153
+ description: 'Skip fetching B4M-web skills for this run (local files only)',
154
+ default: false,
155
+ })
118
156
  .option('reset-api', {
119
157
  type: 'boolean',
120
158
  description: 'Reset the API URL to the Bike4Mind default and clear auth tokens, then exit',
@@ -196,6 +234,42 @@ if (argv['add-dir'] && argv['add-dir'].length > 0) {
196
234
  if (argv['ollama-host']) {
197
235
  process.env.B4M_OLLAMA_HOST = argv['ollama-host'];
198
236
  }
237
+ if (argv['no-remote-skills']) {
238
+ process.env.B4M_NO_REMOTE_SKILLS = '1';
239
+ }
240
+
241
+ // ─── claude-compatible flags → B4M_* env (read by src/index.tsx init) ─────────
242
+ // Mirrors the established bin→env→init channel (cf. --add-dir → B4M_ADDITIONAL_DIRS).
243
+ if (argv['mcp-config']) {
244
+ process.env.B4M_MCP_CONFIG_FILE = resolve(argv['mcp-config']);
245
+ }
246
+ if (argv['strict-mcp-config']) {
247
+ process.env.B4M_STRICT_MCP_CONFIG = '1';
248
+ }
249
+ if (argv['append-system-prompt']) {
250
+ process.env.B4M_APPEND_SYSTEM_PROMPT = argv['append-system-prompt'];
251
+ }
252
+ if (argv.allowedTools && argv.allowedTools.length > 0) {
253
+ // Each element may itself be a space-separated list (the host's board pane passes
254
+ // "a b c" as a single argv token); flatten on whitespace into discrete patterns.
255
+ const patterns = argv.allowedTools.flatMap((s) => String(s).split(/\s+/)).filter(Boolean);
256
+ process.env.B4M_ALLOWED_TOOLS = JSON.stringify(patterns);
257
+ }
258
+ if (argv.settings) {
259
+ process.env.B4M_SETTINGS_JSON = argv.settings;
260
+ }
261
+ if (argv['session-id']) {
262
+ process.env.B4M_SESSION_ID = argv['session-id'];
263
+ }
264
+ if (argv.resume) {
265
+ process.env.B4M_RESUME_ID = argv.resume;
266
+ }
267
+ // Positional task (claude `<prompt>` form): seeds AND submits turn 1, stays interactive.
268
+ // Only when it's not a known subcommand and headless -p wasn't used.
269
+ const KNOWN_SUBCOMMANDS = new Set(['mcp', 'update', 'doctor']);
270
+ if (argv.prompt === undefined && argv._.length > 0 && !KNOWN_SUBCOMMANDS.has(String(argv._[0]))) {
271
+ process.env.B4M_INITIAL_PROMPT = String(argv._[0]);
272
+ }
199
273
 
200
274
  // Auto-detect environment: prefer production mode when dist exists
201
275
  const distPath = join(__dirname, '../dist/index.mjs');