neuro-cli 4.1.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -0
  3. package/dist/advisor/advisor.d.ts +50 -0
  4. package/dist/advisor/advisor.js +178 -0
  5. package/dist/agents/base.d.ts +62 -0
  6. package/dist/agents/base.js +215 -0
  7. package/dist/agents/orchestrator.d.ts +46 -0
  8. package/dist/agents/orchestrator.js +192 -0
  9. package/dist/agents/team.d.ts +51 -0
  10. package/dist/agents/team.js +210 -0
  11. package/dist/api/models.d.ts +23 -0
  12. package/dist/api/models.js +514 -0
  13. package/dist/api/ollama.d.ts +153 -0
  14. package/dist/api/ollama.js +751 -0
  15. package/dist/api/openrouter.d.ts +55 -0
  16. package/dist/api/openrouter.js +223 -0
  17. package/dist/commands/commands.d.ts +43 -0
  18. package/dist/commands/commands.js +308 -0
  19. package/dist/config/config.d.ts +8 -0
  20. package/dist/config/config.js +311 -0
  21. package/dist/context/compaction.d.ts +54 -0
  22. package/dist/context/compaction.js +251 -0
  23. package/dist/context/custom-agents.d.ts +107 -0
  24. package/dist/context/custom-agents.js +397 -0
  25. package/dist/context/custom-tools.d.ts +120 -0
  26. package/dist/context/custom-tools.js +564 -0
  27. package/dist/context/git-checkpoint.d.ts +52 -0
  28. package/dist/context/git-checkpoint.js +240 -0
  29. package/dist/context/neuro-md.d.ts +48 -0
  30. package/dist/context/neuro-md.js +202 -0
  31. package/dist/context/neuroignore.d.ts +102 -0
  32. package/dist/context/neuroignore.js +441 -0
  33. package/dist/context/repo-map.d.ts +38 -0
  34. package/dist/context/repo-map.js +220 -0
  35. package/dist/context/skill-standard.d.ts +262 -0
  36. package/dist/context/skill-standard.js +1156 -0
  37. package/dist/context/skill-system.d.ts +75 -0
  38. package/dist/context/skill-system.js +578 -0
  39. package/dist/context/tree-sitter.d.ts +99 -0
  40. package/dist/context/tree-sitter.js +1956 -0
  41. package/dist/core/acp.d.ts +325 -0
  42. package/dist/core/acp.js +1498 -0
  43. package/dist/core/api-server.d.ts +143 -0
  44. package/dist/core/api-server.js +550 -0
  45. package/dist/core/approval.d.ts +81 -0
  46. package/dist/core/approval.js +432 -0
  47. package/dist/core/auto-compact.d.ts +127 -0
  48. package/dist/core/auto-compact.js +436 -0
  49. package/dist/core/auto-mode.d.ts +232 -0
  50. package/dist/core/auto-mode.js +831 -0
  51. package/dist/core/background-session.d.ts +166 -0
  52. package/dist/core/background-session.js +696 -0
  53. package/dist/core/cicd.d.ts +257 -0
  54. package/dist/core/cicd.js +1443 -0
  55. package/dist/core/cloud-sync.d.ts +156 -0
  56. package/dist/core/cloud-sync.js +582 -0
  57. package/dist/core/code-review.d.ts +132 -0
  58. package/dist/core/code-review.js +1191 -0
  59. package/dist/core/completion.d.ts +49 -0
  60. package/dist/core/completion.js +384 -0
  61. package/dist/core/context.d.ts +38 -0
  62. package/dist/core/context.js +144 -0
  63. package/dist/core/diff-preview.d.ts +35 -0
  64. package/dist/core/diff-preview.js +173 -0
  65. package/dist/core/doom-loop.d.ts +51 -0
  66. package/dist/core/doom-loop.js +179 -0
  67. package/dist/core/engine.d.ts +183 -0
  68. package/dist/core/engine.js +942 -0
  69. package/dist/core/extended-thinking.d.ts +103 -0
  70. package/dist/core/extended-thinking.js +269 -0
  71. package/dist/core/fallback.d.ts +54 -0
  72. package/dist/core/fallback.js +104 -0
  73. package/dist/core/git-worktree.d.ts +139 -0
  74. package/dist/core/git-worktree.js +614 -0
  75. package/dist/core/headless.d.ts +30 -0
  76. package/dist/core/headless.js +101 -0
  77. package/dist/core/i18n.d.ts +83 -0
  78. package/dist/core/i18n.js +739 -0
  79. package/dist/core/linting.d.ts +129 -0
  80. package/dist/core/linting.js +699 -0
  81. package/dist/core/model-router.d.ts +109 -0
  82. package/dist/core/model-router.js +581 -0
  83. package/dist/core/multi-model.d.ts +243 -0
  84. package/dist/core/multi-model.js +1099 -0
  85. package/dist/core/multi-session.d.ts +144 -0
  86. package/dist/core/multi-session.js +442 -0
  87. package/dist/core/multimodal.d.ts +125 -0
  88. package/dist/core/multimodal.js +286 -0
  89. package/dist/core/observability.d.ts +93 -0
  90. package/dist/core/observability.js +737 -0
  91. package/dist/core/os-sandbox.d.ts +122 -0
  92. package/dist/core/os-sandbox.js +1193 -0
  93. package/dist/core/outcome-grading.d.ts +228 -0
  94. package/dist/core/outcome-grading.js +1123 -0
  95. package/dist/core/output-styles.d.ts +57 -0
  96. package/dist/core/output-styles.js +382 -0
  97. package/dist/core/parallel-agents.d.ts +183 -0
  98. package/dist/core/parallel-agents.js +563 -0
  99. package/dist/core/plugin-bundle.d.ts +236 -0
  100. package/dist/core/plugin-bundle.js +887 -0
  101. package/dist/core/plugin-sdk.d.ts +139 -0
  102. package/dist/core/plugin-sdk.js +273 -0
  103. package/dist/core/prompt-cache.d.ts +163 -0
  104. package/dist/core/prompt-cache.js +599 -0
  105. package/dist/core/sandbox.d.ts +127 -0
  106. package/dist/core/sandbox.js +369 -0
  107. package/dist/core/scheduled-tasks.d.ts +151 -0
  108. package/dist/core/scheduled-tasks.js +502 -0
  109. package/dist/core/security-scanner.d.ts +160 -0
  110. package/dist/core/security-scanner.js +1494 -0
  111. package/dist/core/session.d.ts +83 -0
  112. package/dist/core/session.js +269 -0
  113. package/dist/core/shell-completion.d.ts +51 -0
  114. package/dist/core/shell-completion.js +674 -0
  115. package/dist/core/smart-monitor.d.ts +146 -0
  116. package/dist/core/smart-monitor.js +1199 -0
  117. package/dist/core/spec-driven.d.ts +233 -0
  118. package/dist/core/spec-driven.js +1485 -0
  119. package/dist/core/spending-warnings.d.ts +123 -0
  120. package/dist/core/spending-warnings.js +456 -0
  121. package/dist/core/sub-agent.d.ts +298 -0
  122. package/dist/core/sub-agent.js +1023 -0
  123. package/dist/core/telemetry.d.ts +157 -0
  124. package/dist/core/telemetry.js +412 -0
  125. package/dist/core/terminal-ux.d.ts +134 -0
  126. package/dist/core/terminal-ux.js +649 -0
  127. package/dist/core/testing.d.ts +146 -0
  128. package/dist/core/testing.js +1200 -0
  129. package/dist/core/types.d.ts +439 -0
  130. package/dist/core/types.js +6 -0
  131. package/dist/core/undo-redo.d.ts +112 -0
  132. package/dist/core/undo-redo.js +290 -0
  133. package/dist/core/updater.d.ts +159 -0
  134. package/dist/core/updater.js +608 -0
  135. package/dist/core/vim-mode.d.ts +151 -0
  136. package/dist/core/vim-mode.js +771 -0
  137. package/dist/core/voice.d.ts +137 -0
  138. package/dist/core/voice.js +538 -0
  139. package/dist/core/web-dashboard.d.ts +109 -0
  140. package/dist/core/web-dashboard.js +484 -0
  141. package/dist/hooks/hooks.d.ts +74 -0
  142. package/dist/hooks/hooks.js +160 -0
  143. package/dist/hooks/llm-evaluator.d.ts +165 -0
  144. package/dist/hooks/llm-evaluator.js +560 -0
  145. package/dist/index.d.ts +3 -0
  146. package/dist/index.js +1186 -0
  147. package/dist/lsp/lsp-manager.d.ts +63 -0
  148. package/dist/lsp/lsp-manager.js +351 -0
  149. package/dist/mcp/client.d.ts +133 -0
  150. package/dist/mcp/client.js +684 -0
  151. package/dist/mcp/mcp-apps.d.ts +70 -0
  152. package/dist/mcp/mcp-apps.js +1007 -0
  153. package/dist/tools/bash.d.ts +5 -0
  154. package/dist/tools/bash.js +195 -0
  155. package/dist/tools/browser.d.ts +92 -0
  156. package/dist/tools/browser.js +1570 -0
  157. package/dist/tools/extended.d.ts +6 -0
  158. package/dist/tools/extended.js +191 -0
  159. package/dist/tools/file.d.ts +10 -0
  160. package/dist/tools/file.js +382 -0
  161. package/dist/tools/github.d.ts +389 -0
  162. package/dist/tools/github.js +759 -0
  163. package/dist/tools/index.d.ts +9 -0
  164. package/dist/tools/index.js +40 -0
  165. package/dist/tools/memory.d.ts +6 -0
  166. package/dist/tools/memory.js +197 -0
  167. package/dist/tools/registry.d.ts +29 -0
  168. package/dist/tools/registry.js +64 -0
  169. package/dist/tools/web.d.ts +6 -0
  170. package/dist/tools/web.js +150 -0
  171. package/dist/ui/renderer.d.ts +97 -0
  172. package/dist/ui/renderer.js +279 -0
  173. package/dist/ui/theme.d.ts +27 -0
  174. package/dist/ui/theme.js +106 -0
  175. package/package.json +83 -0
@@ -0,0 +1,160 @@
1
+ // ============================================================
2
+ // NeuroCLI - Hooks System
3
+ // Lifecycle event hooks (like Claude Code's 30+ events)
4
+ // ============================================================
5
+ export class HooksSystem {
6
+ hooks = new Map();
7
+ globalHooks = [];
8
+ /**
9
+ * Register a hook
10
+ */
11
+ register(hook) {
12
+ if (!this.hooks.has(hook.event)) {
13
+ this.hooks.set(hook.event, []);
14
+ }
15
+ this.hooks.get(hook.event).push(hook);
16
+ }
17
+ /**
18
+ * Register a global hook that fires on all events
19
+ */
20
+ registerGlobal(hook) {
21
+ this.globalHooks.push(hook);
22
+ }
23
+ /**
24
+ * Unregister a hook
25
+ */
26
+ unregister(event, index) {
27
+ const hooks = this.hooks.get(event);
28
+ if (hooks)
29
+ hooks.splice(index, 1);
30
+ }
31
+ /**
32
+ * Get all hooks for an event
33
+ */
34
+ getHooks(event) {
35
+ return this.hooks.get(event) || [];
36
+ }
37
+ /**
38
+ * Execute all hooks for an event
39
+ */
40
+ async execute(event, context) {
41
+ const hooks = [
42
+ ...this.globalHooks.filter(h => h.enabled !== false),
43
+ ...(this.hooks.get(event) || []).filter(h => h.enabled !== false),
44
+ ];
45
+ // Filter by matcher
46
+ const matchingHooks = hooks.filter(h => {
47
+ if (!h.matcher)
48
+ return true;
49
+ if (context.toolName) {
50
+ return new RegExp(h.matcher).test(context.toolName);
51
+ }
52
+ return true;
53
+ });
54
+ for (const hook of matchingHooks) {
55
+ const result = await this.executeHook(hook, context);
56
+ if (result.action === 'block') {
57
+ return result; // Stop on block
58
+ }
59
+ if (result.action === 'modify' && result.modifiedArgs) {
60
+ context.toolArgs = { ...context.toolArgs, ...result.modifiedArgs };
61
+ }
62
+ if (result.additionalContext) {
63
+ // Inject additional context for the LLM
64
+ }
65
+ }
66
+ return { action: 'continue' };
67
+ }
68
+ /**
69
+ * Execute a single hook
70
+ */
71
+ async executeHook(hook, context) {
72
+ switch (hook.type) {
73
+ case 'command':
74
+ return this.executeCommandHook(hook, context);
75
+ case 'http':
76
+ return this.executeHttpHook(hook, context);
77
+ case 'prompt':
78
+ return { action: 'continue', additionalContext: hook.prompt };
79
+ case 'agent':
80
+ return { action: 'continue', additionalContext: hook.command };
81
+ default:
82
+ return { action: 'continue' };
83
+ }
84
+ }
85
+ async executeCommandHook(hook, context) {
86
+ if (!hook.command)
87
+ return { action: 'continue' };
88
+ try {
89
+ const { execSync } = await import('child_process');
90
+ const env = {
91
+ NEURO_EVENT: context.event,
92
+ NEURO_TOOL: context.toolName || '',
93
+ NEURO_SESSION: context.sessionId,
94
+ NEURO_CWD: context.workingDirectory,
95
+ };
96
+ const result = execSync(hook.command, {
97
+ encoding: 'utf-8',
98
+ cwd: context.workingDirectory,
99
+ timeout: 10000,
100
+ env: { ...process.env, ...env },
101
+ }).trim();
102
+ // Parse hook output for actions
103
+ if (result.startsWith('BLOCK:')) {
104
+ return { action: 'block', reason: result.replace('BLOCK:', '').trim() };
105
+ }
106
+ if (result.startsWith('CONTEXT:')) {
107
+ return { action: 'continue', additionalContext: result.replace('CONTEXT:', '').trim() };
108
+ }
109
+ return { action: 'continue' };
110
+ }
111
+ catch (error) {
112
+ return { action: 'continue', reason: `Hook error: ${error}` };
113
+ }
114
+ }
115
+ async executeHttpHook(hook, context) {
116
+ if (!hook.url)
117
+ return { action: 'continue' };
118
+ try {
119
+ const response = await fetch(hook.url, {
120
+ method: 'POST',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify(context),
123
+ signal: AbortSignal.timeout(5000),
124
+ });
125
+ if (response.ok) {
126
+ const data = await response.json();
127
+ return {
128
+ action: data.action || 'continue',
129
+ additionalContext: data.context,
130
+ reason: data.reason,
131
+ };
132
+ }
133
+ return { action: 'continue' };
134
+ }
135
+ catch {
136
+ return { action: 'continue', reason: 'HTTP hook failed' };
137
+ }
138
+ }
139
+ /**
140
+ * Load hooks from config
141
+ */
142
+ loadFromConfig(config) {
143
+ if (config.hooks) {
144
+ for (const hook of config.hooks) {
145
+ this.register(hook);
146
+ }
147
+ }
148
+ }
149
+ /**
150
+ * List all registered hooks
151
+ */
152
+ list() {
153
+ const result = [];
154
+ for (const [event, hooks] of this.hooks) {
155
+ result.push({ event, hooks });
156
+ }
157
+ return result;
158
+ }
159
+ }
160
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1,165 @@
1
+ import { OpenRouterClient } from '../api/openrouter.js';
2
+ import { FileChange } from '../core/types.js';
3
+ import { HookEvent } from './hooks.js';
4
+ /** A hook backed by an LLM evaluator instead of a shell command. */
5
+ export interface LLMEvaluatorHook {
6
+ /** Unique identifier for this evaluator. */
7
+ id: string;
8
+ /** Human-readable name. */
9
+ name: string;
10
+ /** Lifecycle event this evaluator subscribes to. */
11
+ event: HookEvent;
12
+ /** Model identifier used for evaluation (e.g. "google/gemma-4-31b-it:free"). */
13
+ evaluatorModel: string;
14
+ /** Evaluation criteria / instructions for the LLM. */
15
+ rubric: string;
16
+ /** Default action when the evaluator is undecided. */
17
+ action: 'approve' | 'deny' | 'modify' | 'ask-user';
18
+ /** Maximum tokens the evaluator may generate. */
19
+ maxTokens: number;
20
+ /** Sampling temperature for the evaluator. */
21
+ temperature: number;
22
+ /** Whether to cache evaluation decisions. */
23
+ cacheDecisions: boolean;
24
+ /** Time-to-live for cached decisions in seconds. */
25
+ cacheTTL: number;
26
+ /** Optional glob-style matcher to filter by tool name. */
27
+ matcher?: string;
28
+ /** Whether this evaluator is enabled. */
29
+ enabled?: boolean;
30
+ /** Optional provider override ("openrouter" | "ollama"). */
31
+ provider?: 'openrouter' | 'ollama';
32
+ /** Ollama base URL (only used when provider is "ollama"). */
33
+ ollamaBaseUrl?: string;
34
+ }
35
+ /** Context passed to an evaluator describing the pending action. */
36
+ export interface EvaluationContext {
37
+ /** Name of the tool about to be (or having been) called. */
38
+ toolName: string;
39
+ /** Arguments that will be passed to the tool. */
40
+ toolArgs: Record<string, any>;
41
+ /** File changes that the tool would cause (if known). */
42
+ fileChanges?: FileChange[];
43
+ /** Output from the tool (only available in post-tool hooks). */
44
+ commandOutput?: string;
45
+ /** Recent conversation messages for situational awareness. */
46
+ conversationContext?: string;
47
+ /** Contents of NEURO.md for project-level context. */
48
+ projectContext?: string;
49
+ }
50
+ /** Result returned by an LLM evaluator. */
51
+ export interface EvaluationResult {
52
+ /** The evaluator's decision. */
53
+ decision: 'approve' | 'deny' | 'modify' | 'ask-user';
54
+ /** Confidence level between 0 and 1. */
55
+ confidence: number;
56
+ /** Free-text reasoning from the evaluator. */
57
+ reasoning: string;
58
+ /** Suggested modified tool arguments (only when decision is "modify"). */
59
+ suggestedModification?: Record<string, any>;
60
+ /** Question to surface to the user (only when decision is "ask-user"). */
61
+ userQuestion?: string;
62
+ /** Whether this result was served from cache. */
63
+ cached: boolean;
64
+ /** The model that was actually used for the evaluation. */
65
+ modelUsed: string;
66
+ /** Number of tokens consumed by the evaluation call. */
67
+ tokensUsed: number;
68
+ /** Wall-clock duration of the evaluation in milliseconds. */
69
+ duration: number;
70
+ }
71
+ /** Aggregate statistics about evaluator usage. */
72
+ export interface EvaluatorStats {
73
+ totalEvaluations: number;
74
+ totalTokensUsed: number;
75
+ totalCost: number;
76
+ cacheHits: number;
77
+ cacheMisses: number;
78
+ decisions: Record<'approve' | 'deny' | 'modify' | 'ask-user', number>;
79
+ byEvaluator: Record<string, {
80
+ evaluations: number;
81
+ tokensUsed: number;
82
+ cost: number;
83
+ }>;
84
+ }
85
+ /** Configuration for the LLMEvaluatorManager. */
86
+ export interface EvaluatorConfig {
87
+ /** Default model when none is specified on a hook. */
88
+ defaultModel?: string;
89
+ /** Default rubric when none is specified. */
90
+ defaultRubric?: string;
91
+ /** Confidence threshold below which decisions escalate to "ask-user". */
92
+ confidenceThreshold?: number;
93
+ /** Global toggle for caching. */
94
+ cacheEnabled?: boolean;
95
+ /** Default cache TTL in seconds. */
96
+ defaultCacheTTL?: number;
97
+ /** Maximum number of cache entries. */
98
+ maxCacheEntries?: number;
99
+ /** Ollama base URL for local evaluation models. */
100
+ ollamaBaseUrl?: string;
101
+ }
102
+ export declare class LLMEvaluatorManager {
103
+ private apiClient;
104
+ private evaluators;
105
+ private eventIndex;
106
+ private cache;
107
+ private stats;
108
+ private readonly defaultModel;
109
+ private readonly defaultRubric;
110
+ private readonly confidenceThreshold;
111
+ private readonly cacheEnabled;
112
+ private readonly defaultCacheTTL;
113
+ private readonly maxCacheEntries;
114
+ private readonly ollamaBaseUrl;
115
+ constructor(apiClient: OpenRouterClient, config?: EvaluatorConfig);
116
+ /** Register a new LLM evaluator hook. */
117
+ registerEvaluator(hook: LLMEvaluatorHook): void;
118
+ /** Remove a registered evaluator by its id. */
119
+ unregisterEvaluator(id: string): void;
120
+ /** Return all registered evaluators. */
121
+ listEvaluators(): LLMEvaluatorHook[];
122
+ /**
123
+ * Run all evaluators registered for `event` against the given `context`.
124
+ * Evaluators are executed sequentially in registration order.
125
+ * The first "deny" short-circuits; "modify" updates the context for
126
+ * subsequent evaluators; "ask-user" is collected and returned.
127
+ */
128
+ evaluate(event: HookEvent, context: EvaluationContext): Promise<EvaluationResult>;
129
+ private evaluateSingle;
130
+ private parseEvaluationResponse;
131
+ private getFromCache;
132
+ private storeInCache;
133
+ /** Remove all cached decisions. */
134
+ clearCache(): void;
135
+ /**
136
+ * Scan `dir/.neuro/hooks/` for YAML files with frontmatter and register
137
+ * them as evaluators.
138
+ *
139
+ * Expected file format:
140
+ * ```
141
+ * ---
142
+ * id: my-evaluator
143
+ * name: My Safety Evaluator
144
+ * event: BeforeTool
145
+ * evaluatorModel: google/gemma-4-31b-it:free
146
+ * action: deny
147
+ * maxTokens: 256
148
+ * temperature: 0.1
149
+ * cacheDecisions: true
150
+ * cacheTTL: 300
151
+ * matcher: "write|delete|exec"
152
+ * provider: openrouter
153
+ * ---
154
+ * Never allow modifications to .env files or deletion of test files.
155
+ * ```
156
+ *
157
+ * The body (after frontmatter) becomes the rubric.
158
+ */
159
+ loadFromConfig(dir: string): Promise<void>;
160
+ /** Return a snapshot of aggregate evaluation statistics. */
161
+ getStats(): EvaluatorStats;
162
+ /** Rough token estimator when exact counts are unavailable. */
163
+ private estimateTokens;
164
+ }
165
+ //# sourceMappingURL=llm-evaluator.d.ts.map