@bahulam/code 0.1.11 → 0.1.13
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/package.json +1 -1
- package/src/auth/tarang-auth.mjs +313 -0
- package/src/commands/agent.mjs +7 -7
- package/src/commands/install.mjs +295 -0
- package/src/commands/plugin-manage.mjs +280 -88
- package/src/config/cli-args.mjs +16 -0
- package/src/config/settings-loader.mjs +15 -0
- package/src/core/background-tasks.mjs +186 -0
- package/src/core/headless.mjs +54 -3
- package/src/core/local-agent.mjs +10 -1
- package/src/core/risk-tier.mjs +1 -0
- package/src/core/stream-client.mjs +95 -15
- package/src/core/tool-executor.mjs +266 -15
- package/src/local-service/agent-relay.mjs +1 -1
- package/src/local-service/server.mjs +116 -14
- package/src/orchestration/approval.mjs +30 -0
- package/src/orchestration/completion-triggers.mjs +40 -0
- package/src/orchestration/dispatch.mjs +118 -0
- package/src/orchestration/events.mjs +19 -0
- package/src/orchestration/graph.mjs +126 -0
- package/src/orchestration/node-runner.mjs +193 -0
- package/src/orchestration/runner.mjs +200 -0
- package/src/plugins/executor.mjs +2 -2
- package/src/plugins/manifest.mjs +30 -27
- package/src/plugins/pi-compat/loader-hook.mjs +45 -0
- package/src/plugins/pi-compat/probe.mjs +294 -0
- package/src/plugins/pi-compat/scaffold.mjs +487 -0
- package/src/plugins/pi-compat/shim.mjs +134 -0
- package/src/plugins/pi-compose.mjs +147 -0
- package/src/plugins/preflight.mjs +35 -10
- package/src/plugins/registry.mjs +6 -0
- package/src/terminal/agents.mjs +8 -3
- package/src/terminal/main.mjs +39 -7
- package/src/terminal/paste-input.mjs +23 -0
- package/src/terminal/repl-render.mjs +65 -10
- package/src/terminal/repl-state.mjs +4 -2
- package/src/terminal/repl.mjs +624 -103
- package/src/tools/agent.mjs +6 -2
- package/src/tools/registry.mjs +107 -4
- package/src/ui/input-dock.mjs +5 -2
- package/src/ui/slash-commands.mjs +1 -1
- package/src/ui/sub-agent.mjs +14 -8
package/src/tools/agent.mjs
CHANGED
|
@@ -58,9 +58,13 @@ export const AgentTool = {
|
|
|
58
58
|
_backgroundAgents: new Map(),
|
|
59
59
|
_nextBgId: 0,
|
|
60
60
|
|
|
61
|
-
async call(input) {
|
|
61
|
+
async call(input, options = {}) {
|
|
62
62
|
const model = input.model || process.env.SUBAGENT_MODEL || 'claude-sonnet-4-6';
|
|
63
|
-
const tools = createToolRegistry(
|
|
63
|
+
const tools = createToolRegistry({
|
|
64
|
+
pluginRegistry: options.pluginRegistry || null,
|
|
65
|
+
stateEmit: options.stateEmit || null,
|
|
66
|
+
exposePluginTools: true,
|
|
67
|
+
});
|
|
64
68
|
const permissions = createPermissionChecker({ defaultMode: 'bypassPermissions' });
|
|
65
69
|
|
|
66
70
|
// Build type-specific system prompt prefix
|
package/src/tools/registry.mjs
CHANGED
|
@@ -39,6 +39,7 @@ import { ExploreTool, PlanTool, VerifyTool, DebugTool, RefactorTool } from './me
|
|
|
39
39
|
import { RememberTool } from './remember.mjs';
|
|
40
40
|
import { GenerateImageTool } from './generate-image.mjs';
|
|
41
41
|
import { AnalyzeImageTool } from './analyze-image.mjs';
|
|
42
|
+
import { loadPluginTool } from '../plugins/executor.mjs';
|
|
42
43
|
|
|
43
44
|
const BUILTIN_TOOLS = [
|
|
44
45
|
BashTool,
|
|
@@ -82,12 +83,114 @@ const BUILTIN_TOOLS = [
|
|
|
82
83
|
RefactorTool,
|
|
83
84
|
];
|
|
84
85
|
|
|
85
|
-
export function createToolRegistry(
|
|
86
|
+
export function createToolRegistry({
|
|
87
|
+
pluginRegistry = null,
|
|
88
|
+
stateEmit = null,
|
|
89
|
+
exposePluginTools = false,
|
|
90
|
+
} = {}) {
|
|
86
91
|
const tools = new Map();
|
|
87
92
|
for (const Tool of BUILTIN_TOOLS) {
|
|
88
|
-
|
|
93
|
+
if (Tool === AgentTool) {
|
|
94
|
+
tools.set(Tool.name, {
|
|
95
|
+
...Tool,
|
|
96
|
+
async call(input, options = {}) {
|
|
97
|
+
return Tool.call(input, {
|
|
98
|
+
...options,
|
|
99
|
+
pluginRegistry: options.pluginRegistry || pluginRegistry,
|
|
100
|
+
stateEmit: options.stateEmit || stateEmit,
|
|
101
|
+
});
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
tools.set(Tool.name, Tool);
|
|
106
|
+
}
|
|
89
107
|
}
|
|
90
108
|
|
|
109
|
+
const pluginStateHandles = new Map();
|
|
110
|
+
async function pluginStateFor(pluginName) {
|
|
111
|
+
if (!pluginName) return null;
|
|
112
|
+
if (pluginStateHandles.has(pluginName)) return pluginStateHandles.get(pluginName);
|
|
113
|
+
const { makePluginState } = await import('../plugins/state.mjs');
|
|
114
|
+
const state = makePluginState(pluginName, { emit: stateEmit });
|
|
115
|
+
pluginStateHandles.set(pluginName, state);
|
|
116
|
+
return state;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function registerPluginToolsFromRegistry() {
|
|
120
|
+
if (!pluginRegistry) return;
|
|
121
|
+
for (const toolDef of pluginRegistry.listTools?.() || []) {
|
|
122
|
+
const name = String(toolDef.name || '').trim();
|
|
123
|
+
if (!name || tools.has(name)) continue;
|
|
124
|
+
const pluginName = toolDef._plugin_name || toolDef.plugin_name || null;
|
|
125
|
+
if (toolDef._composed?.kind === 'pi') {
|
|
126
|
+
tools.set(name, {
|
|
127
|
+
name,
|
|
128
|
+
description: toolDef.description || '',
|
|
129
|
+
inputSchema: toolDef.input_schema || toolDef.parameters || { type: 'object', properties: {} },
|
|
130
|
+
validateInput() { return []; },
|
|
131
|
+
async call() {
|
|
132
|
+
return {
|
|
133
|
+
success: false,
|
|
134
|
+
output: `Composed pi tool '${name}' is registered but pi runtime execution is not wired yet`,
|
|
135
|
+
_tool: name,
|
|
136
|
+
_plugin: pluginName,
|
|
137
|
+
_composed: toolDef._composed,
|
|
138
|
+
_blocked: true,
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
tools.set(name, {
|
|
145
|
+
name,
|
|
146
|
+
description: toolDef.description || '',
|
|
147
|
+
inputSchema: toolDef.input_schema || toolDef.parameters || { type: 'object', properties: {} },
|
|
148
|
+
validateInput() { return []; },
|
|
149
|
+
async call(input, options = {}) {
|
|
150
|
+
const handler = await loadPluginTool(toolDef._plugin_dir, toolDef.tool || toolDef.handler);
|
|
151
|
+
if (!handler) {
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
output: `Plugin tool module could not be loaded: ${name}`,
|
|
155
|
+
_tool: name,
|
|
156
|
+
_plugin: pluginName,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const handlerOpts = {
|
|
160
|
+
...options,
|
|
161
|
+
pluginName,
|
|
162
|
+
get state() {
|
|
163
|
+
if (this._stateP) return this._stateP;
|
|
164
|
+
this._stateP = pluginStateFor(pluginName);
|
|
165
|
+
return this._stateP;
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
try {
|
|
169
|
+
const result = await handler.call(input || {}, handlerOpts);
|
|
170
|
+
if (result && typeof result === 'object' && 'success' in result) {
|
|
171
|
+
return { ...result, _tool: name, _plugin: pluginName };
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
success: true,
|
|
175
|
+
output: typeof result === 'string' ? result : JSON.stringify(result),
|
|
176
|
+
_tool: name,
|
|
177
|
+
_plugin: pluginName,
|
|
178
|
+
};
|
|
179
|
+
} catch (err) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
output: `Plugin tool error (${name}): ${err.message}`,
|
|
183
|
+
_tool: name,
|
|
184
|
+
_plugin: pluginName,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (exposePluginTools) registerPluginToolsFromRegistry();
|
|
193
|
+
|
|
91
194
|
const registry = {
|
|
92
195
|
list() {
|
|
93
196
|
return [...tools.values()].map(t => ({
|
|
@@ -97,12 +200,12 @@ export function createToolRegistry() {
|
|
|
97
200
|
}));
|
|
98
201
|
},
|
|
99
202
|
|
|
100
|
-
async call(name, input) {
|
|
203
|
+
async call(name, input, options = {}) {
|
|
101
204
|
const tool = tools.get(name);
|
|
102
205
|
if (!tool) throw new Error(`Unknown tool: ${name}`);
|
|
103
206
|
const errors = tool.validateInput?.(input) || [];
|
|
104
207
|
if (errors.length > 0) return `Validation error: ${errors.join(', ')}`;
|
|
105
|
-
const result = await tool.call(input);
|
|
208
|
+
const result = await tool.call(input, options);
|
|
106
209
|
|
|
107
210
|
return result;
|
|
108
211
|
},
|
package/src/ui/input-dock.mjs
CHANGED
|
@@ -672,10 +672,13 @@ export function clearInputPrompt() {
|
|
|
672
672
|
return true;
|
|
673
673
|
}
|
|
674
674
|
|
|
675
|
-
export function renderDockInput(prefix, value, { context = '', tips = '', meta = '', cursor = null } = {}) {
|
|
675
|
+
export function renderDockInput(prefix, value, { context = '', tips = '', meta = '', cursor = null, fixedRows = null } = {}) {
|
|
676
676
|
if (!mounted) return false;
|
|
677
677
|
contentTrackingActive = false;
|
|
678
|
-
|
|
678
|
+
const requestedRows = fixedRows == null
|
|
679
|
+
? computeInputRowsForBuffer(prefix, value)
|
|
680
|
+
: Math.max(MIN_INPUT_ROWS, Math.min(inputRowsMax, Math.floor(Number(fixedRows) || MIN_INPUT_ROWS)));
|
|
681
|
+
setInputRowsTo(requestedRows);
|
|
679
682
|
renderFrame({ context, tips, meta, prefix, value, cursor, overlayLines: null });
|
|
680
683
|
const layout = layoutInput(prefix, value);
|
|
681
684
|
drawInputLines(layout.lines);
|
|
@@ -143,7 +143,7 @@ export const HELP_GROUPS = [
|
|
|
143
143
|
['/agents', 'List built-in and local agents'],
|
|
144
144
|
['/agents create <name>', 'Create .bahulam/agents/<name>.yaml'],
|
|
145
145
|
['/agents edit <name>', 'Open local agent YAML'],
|
|
146
|
-
['/agents sync [name]', '
|
|
146
|
+
['/agents sync [name]', 'Publish local agents to backend/account reuse'],
|
|
147
147
|
['/run <agent> [instruction]', 'Run a local or built-in agent'],
|
|
148
148
|
['/explore <instruction>', 'Explore code'],
|
|
149
149
|
['/review <instruction>', 'Review code'],
|
package/src/ui/sub-agent.mjs
CHANGED
|
@@ -70,11 +70,12 @@ export function displayQuery(query, max = 140) {
|
|
|
70
70
|
|
|
71
71
|
export function renderSubAgentOpen({ id, type, query, parentDepth } = {}) {
|
|
72
72
|
const t = type || 'sub-agent';
|
|
73
|
-
const depthBefore = _stack.length;
|
|
74
|
-
_stack.push({ id: id || `${t}-${depthBefore}-${tag()}`, type: t, startedAt: Date.now() });
|
|
73
|
+
const depthBefore = Number.isFinite(parentDepth) ? Math.max(0, parentDepth) : _stack.length;
|
|
74
|
+
_stack.push({ id: id || `${t}-${depthBefore}-${tag()}`, type: t, depth: depthBefore, startedAt: Date.now() });
|
|
75
75
|
|
|
76
76
|
const indent = ' '.repeat(2 + depthBefore * 3);
|
|
77
|
-
|
|
77
|
+
// Ordinal labels (explore#2) still get their base type's icon.
|
|
78
|
+
const iconChar = SUB_ICONS[t] || SUB_ICONS[String(t).replace(/#\d+$/, '')] || icons.subAgent;
|
|
78
79
|
const shown = displayQuery(query);
|
|
79
80
|
const head = `${indent}${iconChar} ${paint.brand.data(t)} ${paint.text.dim(`"${shown}"`)}`;
|
|
80
81
|
const tag1 = paint.text.dim('▸ running');
|
|
@@ -95,6 +96,7 @@ export function renderSubAgentOpen({ id, type, query, parentDepth } = {}) {
|
|
|
95
96
|
* and any of `{ costUsd, tokens, durationS, toolCalls, iterations }`.
|
|
96
97
|
*/
|
|
97
98
|
export function renderSubAgentClose({
|
|
99
|
+
id,
|
|
98
100
|
type,
|
|
99
101
|
success = true,
|
|
100
102
|
summary = '',
|
|
@@ -105,12 +107,16 @@ export function renderSubAgentClose({
|
|
|
105
107
|
iterations,
|
|
106
108
|
error,
|
|
107
109
|
} = {}) {
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
// Parallel sub-agents can complete out of stack order. Prefer exact id,
|
|
111
|
+
// then type, and fall back to the latest open entry for legacy streams.
|
|
112
|
+
let idx = -1;
|
|
113
|
+
if (id) idx = _stack.findLastIndex(entry => entry.id === id);
|
|
114
|
+
if (idx < 0 && type) idx = _stack.findLastIndex(entry => entry.type === type);
|
|
115
|
+
if (idx < 0) idx = _stack.length - 1;
|
|
116
|
+
const opened = idx >= 0 ? _stack.splice(idx, 1)[0] : null;
|
|
112
117
|
const t = type || opened?.type || 'sub-agent';
|
|
113
|
-
const
|
|
118
|
+
const closeDepth = Number.isFinite(opened?.depth) ? opened.depth : _stack.length;
|
|
119
|
+
const indent = ' '.repeat(2 + closeDepth * 3);
|
|
114
120
|
|
|
115
121
|
if (!success) {
|
|
116
122
|
const line = `${indent}${paint.text.dim('└')} ${paint.state.danger('✗')} ${paint.text.dim(`${t} agent failed`)}`;
|