@kinqs/brainrouter-cli 0.3.7 → 0.3.8

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 (59) hide show
  1. package/changelog/0.2.0.md +15 -0
  2. package/changelog/0.3.0.md +20 -0
  3. package/changelog/0.3.1.md +22 -0
  4. package/changelog/0.3.2.md +15 -0
  5. package/changelog/0.3.3.md +19 -0
  6. package/changelog/0.3.4.md +20 -0
  7. package/changelog/0.3.5.md +9 -0
  8. package/changelog/0.3.6.md +9 -0
  9. package/changelog/0.3.7.md +20 -0
  10. package/changelog/0.3.8.md +30 -0
  11. package/changelog/README.md +41 -0
  12. package/dist/agent/agent.d.ts +22 -0
  13. package/dist/agent/agent.js +259 -82
  14. package/dist/agent/toolCallRecovery.d.ts +57 -0
  15. package/dist/agent/toolCallRecovery.js +130 -0
  16. package/dist/agent/toolSafety.d.ts +17 -0
  17. package/dist/agent/toolSafety.js +102 -0
  18. package/dist/cli/banner.js +2 -2
  19. package/dist/cli/cliPrompt.js +65 -0
  20. package/dist/cli/commands/config.js +1 -1
  21. package/dist/cli/commands/mcp.d.ts +1 -1
  22. package/dist/cli/commands/mcp.js +29 -7
  23. package/dist/cli/commands/mcpInstall.d.ts +20 -0
  24. package/dist/cli/commands/mcpInstall.js +87 -0
  25. package/dist/cli/commands/orchestration.js +33 -0
  26. package/dist/cli/commands/releaseNotes.d.ts +24 -0
  27. package/dist/cli/commands/releaseNotes.js +109 -0
  28. package/dist/cli/commands/schedule.d.ts +18 -0
  29. package/dist/cli/commands/schedule.js +189 -0
  30. package/dist/cli/commands/ui.js +2 -2
  31. package/dist/cli/ink/Picker.d.ts +6 -0
  32. package/dist/cli/ink/Picker.js +41 -6
  33. package/dist/cli/ink/runChat.js +112 -1
  34. package/dist/cli/ink/toolFormat.d.ts +11 -9
  35. package/dist/cli/ink/toolFormat.js +42 -16
  36. package/dist/cli/repl.d.ts +1 -1
  37. package/dist/cli/repl.js +9 -2
  38. package/dist/config/config.d.ts +1 -1
  39. package/dist/index.js +10 -1
  40. package/dist/memory/briefing.js +4 -4
  41. package/dist/orchestration/tools.d.ts +95 -2
  42. package/dist/orchestration/tools.js +119 -4
  43. package/dist/prompt/systemPrompt.js +5 -4
  44. package/dist/runtime/anthropicAdapter.d.ts +100 -0
  45. package/dist/runtime/anthropicAdapter.js +293 -0
  46. package/dist/runtime/cronParser.d.ts +23 -0
  47. package/dist/runtime/cronParser.js +122 -0
  48. package/dist/runtime/mcpClient.js +1 -1
  49. package/dist/runtime/mcpPool.d.ts +8 -0
  50. package/dist/runtime/mcpPool.js +19 -0
  51. package/dist/runtime/mcpUtils.d.ts +14 -0
  52. package/dist/runtime/mcpUtils.js +23 -0
  53. package/dist/runtime/scheduleTicker.d.ts +33 -0
  54. package/dist/runtime/scheduleTicker.js +99 -0
  55. package/dist/runtime/vendorSnippets.d.ts +45 -0
  56. package/dist/runtime/vendorSnippets.js +153 -0
  57. package/dist/state/scheduleStore.d.ts +37 -0
  58. package/dist/state/scheduleStore.js +64 -0
  59. package/package.json +7 -4
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Per-vendor MCP install snippets (0.3.8-I5 / roadmap §9).
3
+ *
4
+ * Pattern adapted from semble's per-agent install docs
5
+ * (openSrc/semble/src/semble/agents/*.md) — one focused entry per vendor
6
+ * with the exact JSON shape and config file path. Where semble ships
7
+ * markdown, we ship structured templates so the CLI can substitute the
8
+ * user's live profile URL + API key on the fly.
9
+ *
10
+ * Notes
11
+ * - Tool name examples use the single-underscore convention
12
+ * `mcp_<server>_<tool>` (0.3.8-R5 decision).
13
+ * - Each template is pinned to a "verified against vendor docs as of …"
14
+ * comment. Vendor MCP schemas drift; bump the date when you re-verify.
15
+ * - We never auto-write the vendor config file. Print only — direct-write
16
+ * is a future enhancement (roadmap: future item; do not file a follow-up).
17
+ */
18
+ export type VendorSchema = 'stdio' | 'http' | 'sse';
19
+ export interface VendorVars {
20
+ /** Active BrainRouter profile URL (http transport). */
21
+ url: string;
22
+ /** Active BrainRouter profile API key — rendered verbatim into the snippet. */
23
+ apiKey: string;
24
+ /** Server id the user picks in their vendor config (defaults to "brainrouter"). */
25
+ serverId?: string;
26
+ }
27
+ export interface VendorEntry {
28
+ id: string;
29
+ label: string;
30
+ schema: VendorSchema;
31
+ /** Restart note shown after the snippet. */
32
+ restart: string;
33
+ /** Per-OS config file path. POSIX path with `~` for the user's home. */
34
+ configPath: (platform: NodeJS.Platform) => string;
35
+ /** Pure template — returns the JSON object the user should merge into their vendor config. */
36
+ template: (vars: VendorVars) => unknown;
37
+ /** Free-form note (e.g. nested-key location, alternative shape). */
38
+ note?: string;
39
+ }
40
+ /** Render a config path for human display — backslashes on Windows. */
41
+ export declare function displayPath(p: string, platform?: NodeJS.Platform): string;
42
+ export declare const VENDORS: Record<string, VendorEntry>;
43
+ export declare function listVendors(): VendorEntry[];
44
+ export declare function getVendor(id: string): VendorEntry | undefined;
45
+ export declare function renderSnippet(entry: VendorEntry, vars: VendorVars): string;
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Per-vendor MCP install snippets (0.3.8-I5 / roadmap §9).
3
+ *
4
+ * Pattern adapted from semble's per-agent install docs
5
+ * (openSrc/semble/src/semble/agents/*.md) — one focused entry per vendor
6
+ * with the exact JSON shape and config file path. Where semble ships
7
+ * markdown, we ship structured templates so the CLI can substitute the
8
+ * user's live profile URL + API key on the fly.
9
+ *
10
+ * Notes
11
+ * - Tool name examples use the single-underscore convention
12
+ * `mcp_<server>_<tool>` (0.3.8-R5 decision).
13
+ * - Each template is pinned to a "verified against vendor docs as of …"
14
+ * comment. Vendor MCP schemas drift; bump the date when you re-verify.
15
+ * - We never auto-write the vendor config file. Print only — direct-write
16
+ * is a future enhancement (roadmap: future item; do not file a follow-up).
17
+ */
18
+ import os from 'node:os';
19
+ import path from 'node:path';
20
+ // Helpers ------------------------------------------------------------------
21
+ function home(platform) {
22
+ // Tests can override HOME / APPDATA; in production this is os.homedir().
23
+ if (platform === 'win32')
24
+ return process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming');
25
+ return os.homedir();
26
+ }
27
+ /** Render a config path for human display — backslashes on Windows. */
28
+ export function displayPath(p, platform = process.platform) {
29
+ return platform === 'win32' ? p.replace(/\//g, '\\') : p;
30
+ }
31
+ // Vendor definitions -------------------------------------------------------
32
+ export const VENDORS = {
33
+ 'claude-desktop': {
34
+ id: 'claude-desktop',
35
+ label: 'Claude Desktop',
36
+ schema: 'http',
37
+ restart: 'Quit and reopen Claude Desktop fully — it only re-reads this file on cold start.',
38
+ // Verified against Anthropic docs as of 2026-05.
39
+ configPath: (p) => p === 'win32'
40
+ ? path.join(home(p), 'Claude', 'claude_desktop_config.json')
41
+ : p === 'darwin'
42
+ ? path.join(home(p), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json')
43
+ : path.join(home(p), '.config', 'Claude', 'claude_desktop_config.json'),
44
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
45
+ mcpServers: {
46
+ [serverId]: {
47
+ url,
48
+ headers: { Authorization: `Bearer ${apiKey}` },
49
+ },
50
+ },
51
+ }),
52
+ },
53
+ cursor: {
54
+ id: 'cursor',
55
+ label: 'Cursor',
56
+ schema: 'http',
57
+ restart: 'Cursor reloads MCP servers automatically; reopen the MCP panel if the server does not appear.',
58
+ // Verified against Cursor docs as of 2026-05 (~/.cursor/mcp.json).
59
+ configPath: (p) => path.join(home(p), '.cursor', 'mcp.json'),
60
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
61
+ mcpServers: {
62
+ [serverId]: {
63
+ url,
64
+ headers: { Authorization: `Bearer ${apiKey}` },
65
+ },
66
+ },
67
+ }),
68
+ },
69
+ windsurf: {
70
+ id: 'windsurf',
71
+ label: 'Windsurf (Codeium)',
72
+ schema: 'http',
73
+ restart: 'Open the Windsurf MCP panel and click "Refresh" — no full restart needed.',
74
+ // Verified against Codeium docs as of 2026-05 (~/.codeium/windsurf/mcp_config.json).
75
+ configPath: (p) => path.join(home(p), '.codeium', 'windsurf', 'mcp_config.json'),
76
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
77
+ mcpServers: {
78
+ [serverId]: {
79
+ serverUrl: url,
80
+ headers: { Authorization: `Bearer ${apiKey}` },
81
+ },
82
+ },
83
+ }),
84
+ },
85
+ 'vscode-continue': {
86
+ id: 'vscode-continue',
87
+ label: 'VS Code (Continue extension)',
88
+ schema: 'http',
89
+ restart: 'Continue picks up config.json changes live — no reload required.',
90
+ // Verified against Continue docs as of 2026-05. MCP servers live under
91
+ // experimental.modelContextProtocolServers in ~/.continue/config.json.
92
+ configPath: (p) => path.join(home(p), '.continue', 'config.json'),
93
+ note: 'Merge this block into the top-level object — Continue keys MCP servers under `experimental.modelContextProtocolServers`.',
94
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
95
+ experimental: {
96
+ modelContextProtocolServers: [
97
+ {
98
+ name: serverId,
99
+ transport: { type: 'http', url, headers: { Authorization: `Bearer ${apiKey}` } },
100
+ },
101
+ ],
102
+ },
103
+ }),
104
+ },
105
+ zed: {
106
+ id: 'zed',
107
+ label: 'Zed',
108
+ schema: 'http',
109
+ restart: 'Zed reloads settings.json on save; reopen the assistant panel to see the new server.',
110
+ // Verified against Zed docs as of 2026-05. MCP servers live under
111
+ // `context_servers` in settings.json.
112
+ configPath: (p) => path.join(home(p), '.config', 'zed', 'settings.json'),
113
+ note: 'Merge the `context_servers` key into your existing settings.json.',
114
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
115
+ context_servers: {
116
+ [serverId]: {
117
+ source: 'custom',
118
+ url,
119
+ headers: { Authorization: `Bearer ${apiKey}` },
120
+ },
121
+ },
122
+ }),
123
+ },
124
+ cline: {
125
+ id: 'cline',
126
+ label: 'Cline (VS Code)',
127
+ schema: 'http',
128
+ restart: 'Cline reloads MCP servers when this file is saved — toggle the server off/on in the MCP panel if not.',
129
+ // Verified against Cline docs as of 2026-05.
130
+ configPath: (p) => p === 'darwin'
131
+ ? path.join(home(p), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
132
+ : p === 'win32'
133
+ ? path.join(home(p), 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json')
134
+ : path.join(home(p), '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'),
135
+ template: ({ url, apiKey, serverId = 'brainrouter' }) => ({
136
+ mcpServers: {
137
+ [serverId]: {
138
+ url,
139
+ headers: { Authorization: `Bearer ${apiKey}` },
140
+ },
141
+ },
142
+ }),
143
+ },
144
+ };
145
+ export function listVendors() {
146
+ return Object.values(VENDORS);
147
+ }
148
+ export function getVendor(id) {
149
+ return VENDORS[id.toLowerCase()];
150
+ }
151
+ export function renderSnippet(entry, vars) {
152
+ return JSON.stringify(entry.template(vars), null, 2);
153
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Persistent store for `/schedule` jobs.
3
+ *
4
+ * One JSON file per workspace under the user-global brainrouter home
5
+ * (same contract /feedback uses) — writes go through `writeJsonFile`
6
+ * which does the atomic temp-then-rename dance, so a Ctrl-C mid-write
7
+ * can't corrupt the file.
8
+ */
9
+ export type ScheduleKind = 'cron' | 'once';
10
+ export interface ScheduleRecord {
11
+ id: string;
12
+ kind: ScheduleKind;
13
+ /** Cron expression for `cron`, or ISO timestamp for `once`. */
14
+ expr: string;
15
+ /** Slash command to dispatch. Always starts with `/`. */
16
+ command: string;
17
+ /** sessionKey of the REPL that registered the schedule. */
18
+ owner: string;
19
+ createdAt: string;
20
+ enabled: boolean;
21
+ nextRun: string;
22
+ lastRun?: string;
23
+ }
24
+ export declare function loadSchedules(workspaceRoot: string): ScheduleRecord[];
25
+ export declare function saveSchedules(workspaceRoot: string, list: ScheduleRecord[]): void;
26
+ export interface AddScheduleInput {
27
+ kind: ScheduleKind;
28
+ expr: string;
29
+ command: string;
30
+ owner: string;
31
+ nextRun: string;
32
+ enabled?: boolean;
33
+ }
34
+ export declare function addSchedule(workspaceRoot: string, input: AddScheduleInput): ScheduleRecord;
35
+ export declare function removeSchedule(workspaceRoot: string, id: string): boolean;
36
+ export declare function setScheduleEnabled(workspaceRoot: string, id: string, enabled: boolean): boolean;
37
+ export declare function recordFire(workspaceRoot: string, id: string, firedAt: Date, nextRun: string | undefined): void;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Persistent store for `/schedule` jobs.
3
+ *
4
+ * One JSON file per workspace under the user-global brainrouter home
5
+ * (same contract /feedback uses) — writes go through `writeJsonFile`
6
+ * which does the atomic temp-then-rename dance, so a Ctrl-C mid-write
7
+ * can't corrupt the file.
8
+ */
9
+ import crypto from 'node:crypto';
10
+ import { getCliStateFile, readJsonFile, writeJsonFile } from './cliState.js';
11
+ const FILE_NAME = 'schedules.json';
12
+ const EMPTY = { version: 1, schedules: [] };
13
+ function filePath(workspaceRoot) {
14
+ return getCliStateFile(workspaceRoot, FILE_NAME);
15
+ }
16
+ export function loadSchedules(workspaceRoot) {
17
+ return readJsonFile(filePath(workspaceRoot), EMPTY).schedules ?? [];
18
+ }
19
+ export function saveSchedules(workspaceRoot, list) {
20
+ writeJsonFile(filePath(workspaceRoot), { version: 1, schedules: list });
21
+ }
22
+ export function addSchedule(workspaceRoot, input) {
23
+ const list = loadSchedules(workspaceRoot);
24
+ const rec = {
25
+ id: 'sch_' + crypto.randomBytes(4).toString('hex'),
26
+ kind: input.kind,
27
+ expr: input.expr,
28
+ command: input.command,
29
+ owner: input.owner,
30
+ createdAt: new Date().toISOString(),
31
+ enabled: input.enabled ?? true,
32
+ nextRun: input.nextRun,
33
+ };
34
+ list.push(rec);
35
+ saveSchedules(workspaceRoot, list);
36
+ return rec;
37
+ }
38
+ export function removeSchedule(workspaceRoot, id) {
39
+ const list = loadSchedules(workspaceRoot);
40
+ const next = list.filter((s) => s.id !== id);
41
+ if (next.length === list.length)
42
+ return false;
43
+ saveSchedules(workspaceRoot, next);
44
+ return true;
45
+ }
46
+ export function setScheduleEnabled(workspaceRoot, id, enabled) {
47
+ const list = loadSchedules(workspaceRoot);
48
+ const rec = list.find((s) => s.id === id);
49
+ if (!rec)
50
+ return false;
51
+ rec.enabled = enabled;
52
+ saveSchedules(workspaceRoot, list);
53
+ return true;
54
+ }
55
+ export function recordFire(workspaceRoot, id, firedAt, nextRun) {
56
+ const list = loadSchedules(workspaceRoot);
57
+ const rec = list.find((s) => s.id === id);
58
+ if (!rec)
59
+ return;
60
+ rec.lastRun = firedAt.toISOString();
61
+ if (nextRun)
62
+ rec.nextRun = nextRun;
63
+ saveSchedules(workspaceRoot, list);
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinqs/brainrouter-cli",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Memory-native terminal coding agent. Talks to the BrainRouter MCP cognitive engine for recall, skills, capture, persona, focus scenes, and contradiction tracking.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,6 +10,7 @@
10
10
  "files": [
11
11
  "agents",
12
12
  "bin",
13
+ "changelog",
13
14
  "dist",
14
15
  "README.md",
15
16
  ".env.example"
@@ -20,11 +21,13 @@
20
21
  "dev": "tsx src/index.ts",
21
22
  "start": "node dist/index.js",
22
23
  "test": "npm run build && node --test \"dist/**/*.test.js\"",
23
- "prepack": "npm run build && find dist -name '*.test.*' -delete"
24
+ "prepack": "npm run build && find dist -name '*.test.*' -delete",
25
+ "sync-changelog": "rm -rf changelog && mkdir -p changelog && cp ../brainrouter-changelog/*.md changelog/",
26
+ "prepublishOnly": "npm run sync-changelog"
24
27
  },
25
28
  "dependencies": {
26
- "@kinqs/brainrouter-sdk": "^0.3.6",
27
- "@kinqs/brainrouter-types": "^0.3.6",
29
+ "@kinqs/brainrouter-sdk": "^0.3.8",
30
+ "@kinqs/brainrouter-types": "^0.3.8",
28
31
  "@modelcontextprotocol/sdk": "^1.11.0",
29
32
  "chalk": "^5.3.0",
30
33
  "commander": "^12.1.0",