@bahulam/code 0.1.15 → 0.1.17
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/agents/loader.mjs +37 -10
- package/src/agents/registry.mjs +240 -0
- package/src/commands/install.mjs +8 -8
- package/src/commands/plugin-manage.mjs +16 -15
- package/src/commands/plugin.mjs +15 -12
- package/src/core/background-tasks.mjs +29 -3
- package/src/core/headless.mjs +46 -2
- package/src/core/stream-client.mjs +1 -0
- package/src/core/tool-executor.mjs +80 -159
- package/src/local-service/agent-relay.mjs +56 -1
- package/src/local-service/server.mjs +2 -2
- package/src/orchestration/dispatch.mjs +1 -1
- package/src/plugins/executor.mjs +2 -2
- package/src/plugins/loader.mjs +5 -5
- package/src/plugins/manifest.mjs +147 -24
- package/src/plugins/npm-install.mjs +13 -2
- package/src/plugins/pi-compat/scaffold.mjs +45 -29
- package/src/plugins/preflight.mjs +16 -7
- package/src/plugins/registry.mjs +6 -6
- package/src/plugins/state.mjs +141 -2
- package/src/terminal/repl.mjs +62 -56
- package/src/tools/bash.mjs +17 -1
package/src/terminal/repl.mjs
CHANGED
|
@@ -59,7 +59,7 @@ import * as telemetry from '../telemetry/index.mjs';
|
|
|
59
59
|
import { resolveBackendUrl } from '../core/backend-url.mjs';
|
|
60
60
|
import { formatMessageWindow, lowWindowStatus, messagesRemaining } from '../core/rate-limit-display.mjs';
|
|
61
61
|
import { formatAgentErrorGuidance } from '../core/error-guidance.mjs';
|
|
62
|
-
import { BUILTIN_AGENTS,
|
|
62
|
+
import { BUILTIN_AGENTS, runAgentDefinition } from './agents.mjs';
|
|
63
63
|
import { SkillInstaller } from '../skills/installer.mjs';
|
|
64
64
|
import { SkillsLoader } from '../skills/loader.mjs';
|
|
65
65
|
import { openSkillsPicker, formatSkillsList } from './skills-picker.mjs';
|
|
@@ -921,23 +921,35 @@ function printAgentsUsage() {
|
|
|
921
921
|
process.stderr.write(` /agents sync [name]\n`);
|
|
922
922
|
}
|
|
923
923
|
|
|
924
|
-
function printAgentsList() {
|
|
925
|
-
const
|
|
926
|
-
|
|
924
|
+
function printAgentsList(ctx = {}) {
|
|
925
|
+
const agents = ctx.toolExecutor?.filterAgents?.({}) || [
|
|
926
|
+
...listLocalAgents(safeCwd()),
|
|
927
|
+
...BUILTIN_AGENTS.map(agent => ({
|
|
928
|
+
slug: agent.command,
|
|
929
|
+
name: agent.name,
|
|
930
|
+
description: agent.description,
|
|
931
|
+
source_scope: 'platform',
|
|
932
|
+
})),
|
|
933
|
+
];
|
|
934
|
+
const groups = new Map();
|
|
935
|
+
for (const agent of agents) {
|
|
936
|
+
const scope = agent.source_scope || 'unknown';
|
|
937
|
+
if (!groups.has(scope)) groups.set(scope, []);
|
|
938
|
+
groups.get(scope).push(agent);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
process.stderr.write(`\n ${c.bold('Agents')} ${c.dim('platform + project + global + admitted plugin')}\n`);
|
|
927
942
|
process.stderr.write(` ${c.gray('─'.repeat(44))}\n`);
|
|
928
|
-
|
|
929
|
-
process.stderr.write(` ${c.brand(('/' + agent.command).padEnd(14))} ${agent.description}\n`);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
process.stderr.write(`\n ${c.bold('Local Agents')} ${c.dim('.bahulam/agents + ~/.bahulam/agents')}\n`);
|
|
933
|
-
process.stderr.write(` ${c.gray('─'.repeat(44))}\n`);
|
|
934
|
-
if (!local.length) {
|
|
943
|
+
if (!agents.length) {
|
|
935
944
|
process.stderr.write(` ${c.dim('(none)')}\n`);
|
|
936
945
|
} else {
|
|
937
|
-
for (const
|
|
938
|
-
|
|
939
|
-
const
|
|
940
|
-
|
|
946
|
+
for (const [scope, items] of groups) {
|
|
947
|
+
process.stderr.write(` ${c.dim(scope)}\n`);
|
|
948
|
+
for (const agent of items) {
|
|
949
|
+
const model = agent.model ? c.dim(` · ${agent.model}`) : '';
|
|
950
|
+
const desc = agent.description ? ` ${agent.description}` : '';
|
|
951
|
+
process.stderr.write(` ${c.brand(String(agent.slug || agent.command || agent.name).padEnd(18))}${desc}${model}\n`);
|
|
952
|
+
}
|
|
941
953
|
}
|
|
942
954
|
}
|
|
943
955
|
process.stderr.write('\n');
|
|
@@ -949,7 +961,7 @@ async function handleAgentsCommand(rest = '', ctx) {
|
|
|
949
961
|
const action = (parts.shift() || 'list').toLowerCase();
|
|
950
962
|
|
|
951
963
|
if (action === 'list' || action === 'ls') {
|
|
952
|
-
printAgentsList();
|
|
964
|
+
printAgentsList(ctx);
|
|
953
965
|
return;
|
|
954
966
|
}
|
|
955
967
|
|
|
@@ -3186,6 +3198,23 @@ async function prepareDirectAgentRunContext(ctx, instruction = '') {
|
|
|
3186
3198
|
return execContext;
|
|
3187
3199
|
}
|
|
3188
3200
|
|
|
3201
|
+
function makeDispatchContext(ctx) {
|
|
3202
|
+
const creds = ctx.auth?.loadCredentials?.() || {};
|
|
3203
|
+
return {
|
|
3204
|
+
toolExecutor: ctx.toolExecutor,
|
|
3205
|
+
listRunnables: () => ctx.toolExecutor?.listRunnables?.() || [],
|
|
3206
|
+
listLocalWorkflows: () => listLocalWorkflows(safeCwd()),
|
|
3207
|
+
renderEvent,
|
|
3208
|
+
sessionSubstrate: makeSessionSubstrate(ctx),
|
|
3209
|
+
auth: { token: creds.token || null },
|
|
3210
|
+
credentials: {
|
|
3211
|
+
apiKey: process.env.ANTHROPIC_API_KEY || creds.anthropicKey || null,
|
|
3212
|
+
openRouterKey: process.env.OPENROUTER_API_KEY || creds.openRouterKey || null,
|
|
3213
|
+
},
|
|
3214
|
+
cwd: safeCwd(),
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3189
3218
|
function stripWrappingQuotes(value = '') {
|
|
3190
3219
|
const text = String(value || '').trim();
|
|
3191
3220
|
if (text.length >= 2) {
|
|
@@ -3215,10 +3244,7 @@ function printRunUsage(ctx) {
|
|
|
3215
3244
|
process.stderr.write(` ${c.gray('Example: /run docker-analyzer Analyze all running Docker containers')}\n`);
|
|
3216
3245
|
|
|
3217
3246
|
const targets = new Map();
|
|
3218
|
-
for (const agent of listLocalAgents(safeCwd())) addRunTarget(targets, agent);
|
|
3219
|
-
for (const agent of BUILTIN_AGENTS) addRunTarget(targets, agent);
|
|
3220
3247
|
for (const agent of ctx.toolExecutor?.listRunnables?.() || []) addRunTarget(targets, agent);
|
|
3221
|
-
for (const agent of pluginRegistry?.listAgents?.() || []) addRunTarget(targets, agent);
|
|
3222
3248
|
|
|
3223
3249
|
const agents = [...targets.values()].filter(item => item.kind === 'agent').slice(0, 12);
|
|
3224
3250
|
if (agents.length) {
|
|
@@ -3251,28 +3277,8 @@ async function handleRunCommand(rest = '', ctx) {
|
|
|
3251
3277
|
return;
|
|
3252
3278
|
}
|
|
3253
3279
|
|
|
3254
|
-
const
|
|
3255
|
-
const
|
|
3256
|
-
const registeredAgent = ctx.toolExecutor?.listRunnables?.()
|
|
3257
|
-
?.find(agent => localAgentMatches(agent, target));
|
|
3258
|
-
const pluginAgent = pluginRegistry?.listAgents?.()
|
|
3259
|
-
?.find(agent => localAgentMatches(agent, target));
|
|
3260
|
-
const runnableAgent = localAgent || builtinAgent || registeredAgent || pluginAgent;
|
|
3261
|
-
|
|
3262
|
-
const creds = ctx.auth?.loadCredentials?.() || {};
|
|
3263
|
-
const dispatchCtx = {
|
|
3264
|
-
toolExecutor: ctx.toolExecutor,
|
|
3265
|
-
listRunnables: () => ctx.toolExecutor?.listRunnables?.() || [],
|
|
3266
|
-
listLocalWorkflows: () => listLocalWorkflows(safeCwd()),
|
|
3267
|
-
renderEvent,
|
|
3268
|
-
sessionSubstrate: makeSessionSubstrate(ctx),
|
|
3269
|
-
auth: { token: creds.token || null },
|
|
3270
|
-
credentials: {
|
|
3271
|
-
apiKey: process.env.ANTHROPIC_API_KEY || creds.anthropicKey || null,
|
|
3272
|
-
openRouterKey: process.env.OPENROUTER_API_KEY || creds.openRouterKey || null,
|
|
3273
|
-
},
|
|
3274
|
-
cwd: safeCwd(),
|
|
3275
|
-
};
|
|
3280
|
+
const runnableAgent = ctx.toolExecutor?.findAgent?.(target) || null;
|
|
3281
|
+
const dispatchCtx = makeDispatchContext(ctx);
|
|
3276
3282
|
|
|
3277
3283
|
try {
|
|
3278
3284
|
if (!runnableAgent) process.stderr.write(` ${c.dim(`Running workflow '${target}'...`)}\n`);
|
|
@@ -4254,7 +4260,7 @@ async function handleCommand(input, ctx) {
|
|
|
4254
4260
|
process.stderr.write(` ${c.gray(`Example: ${cmd} ${cmd === '/explore' ? 'how does authentication work?' : cmd === '/review' ? 'check src/core/ for bugs' : 'design a caching layer'}`)}\n`);
|
|
4255
4261
|
return;
|
|
4256
4262
|
}
|
|
4257
|
-
return await
|
|
4263
|
+
return await handleRunCommand(`${cmd.slice(1)} ${rest}`, ctx);
|
|
4258
4264
|
}
|
|
4259
4265
|
|
|
4260
4266
|
case '/logout': {
|
|
@@ -4335,6 +4341,18 @@ export async function startTerminalRepl() {
|
|
|
4335
4341
|
return res;
|
|
4336
4342
|
};
|
|
4337
4343
|
|
|
4344
|
+
async function runDelegateFromTool({ agent, slug, instruction, context = {}, options = {} }) {
|
|
4345
|
+
const dispatchCtx = makeDispatchContext(ctx);
|
|
4346
|
+
return await dispatch({
|
|
4347
|
+
type: 'invoke',
|
|
4348
|
+
source: 'tool:delegate',
|
|
4349
|
+
target: { kind: 'agent', slug: slug || agent?.slug, agent },
|
|
4350
|
+
params: { instruction, context },
|
|
4351
|
+
channel: 'local',
|
|
4352
|
+
signal: options.signal,
|
|
4353
|
+
}, dispatchCtx);
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4338
4356
|
function makeToolExecutor({ showIndexStatus = false } = {}) {
|
|
4339
4357
|
const shouldShowIndexStatus = showIndexStatus && process.stderr.isTTY && !term().plain;
|
|
4340
4358
|
let stopIndexSpinner = null;
|
|
@@ -4342,6 +4360,7 @@ export async function startTerminalRepl() {
|
|
|
4342
4360
|
checkpoints,
|
|
4343
4361
|
hookRunner,
|
|
4344
4362
|
pluginRegistry,
|
|
4363
|
+
delegateRunner: runDelegateFromTool,
|
|
4345
4364
|
interactionHandler: askUserInteraction,
|
|
4346
4365
|
onAutoRegisterStart: shouldShowIndexStatus ? (root) => {
|
|
4347
4366
|
const name = path.basename(root || safeCwd()) || root || 'project';
|
|
@@ -4378,20 +4397,7 @@ export async function startTerminalRepl() {
|
|
|
4378
4397
|
// agent through the trigger funnel when they exit. The ctx builder runs
|
|
4379
4398
|
// lazily at fire time so it sees the live tool executor.
|
|
4380
4399
|
registerJobCompletionDispatch(() => {
|
|
4381
|
-
|
|
4382
|
-
return {
|
|
4383
|
-
toolExecutor: ctx.toolExecutor,
|
|
4384
|
-
listRunnables: () => ctx.toolExecutor?.listRunnables?.() || [],
|
|
4385
|
-
listLocalWorkflows: () => listLocalWorkflows(safeCwd()),
|
|
4386
|
-
renderEvent,
|
|
4387
|
-
sessionSubstrate: makeSessionSubstrate(ctx),
|
|
4388
|
-
auth: { token: creds.token || null },
|
|
4389
|
-
credentials: {
|
|
4390
|
-
apiKey: process.env.ANTHROPIC_API_KEY || creds.anthropicKey || null,
|
|
4391
|
-
openRouterKey: process.env.OPENROUTER_API_KEY || creds.openRouterKey || null,
|
|
4392
|
-
},
|
|
4393
|
-
cwd: safeCwd(),
|
|
4394
|
-
};
|
|
4400
|
+
return makeDispatchContext(ctx);
|
|
4395
4401
|
});
|
|
4396
4402
|
|
|
4397
4403
|
let startupOutputRow = 1;
|
package/src/tools/bash.mjs
CHANGED
|
@@ -16,6 +16,15 @@ function stripAnsi(str) {
|
|
|
16
16
|
return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function trimShellBackgroundOperator(command) {
|
|
20
|
+
const raw = String(command || '');
|
|
21
|
+
let i = raw.length - 1;
|
|
22
|
+
while (i >= 0 && /\s/.test(raw[i])) i -= 1;
|
|
23
|
+
if (raw[i] !== '&') return raw;
|
|
24
|
+
if (raw[i - 1] === '&' || raw[i - 1] === '\\') return raw;
|
|
25
|
+
return raw.slice(0, i).trimEnd();
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
const MAX_OUTPUT_BYTES = 1024 * 1024; // 1MB
|
|
20
29
|
const TIMEOUT_TAIL_BYTES = 64 * 1024;
|
|
21
30
|
const TRUNCATION_MARKER = '\n[output truncated at 1MB]';
|
|
@@ -44,7 +53,7 @@ export const BashTool = {
|
|
|
44
53
|
const abortSignal = input.signal || input._signal || null;
|
|
45
54
|
|
|
46
55
|
if (input.run_in_background) {
|
|
47
|
-
return runBackground(input.command, input.cwd);
|
|
56
|
+
return runBackground(trimShellBackgroundOperator(input.command), input.cwd);
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
if (abortSignal?.aborted) {
|
|
@@ -200,6 +209,12 @@ function killProcess(proc, signal) {
|
|
|
200
209
|
try { proc.kill(signal); } catch { /* already exited */ }
|
|
201
210
|
}
|
|
202
211
|
|
|
212
|
+
function unrefChildStdio(proc) {
|
|
213
|
+
for (const stream of [proc?.stdout, proc?.stderr]) {
|
|
214
|
+
try { stream?.unref?.(); } catch { /* best effort */ }
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
203
218
|
// Background jobs store
|
|
204
219
|
const backgroundJobs = new Map();
|
|
205
220
|
let bgJobId = 0;
|
|
@@ -227,6 +242,7 @@ function runBackground(command, cwd) {
|
|
|
227
242
|
});
|
|
228
243
|
|
|
229
244
|
proc.unref();
|
|
245
|
+
unrefChildStdio(proc);
|
|
230
246
|
return `Background job started: id=${id}, pid=${proc.pid}`;
|
|
231
247
|
}
|
|
232
248
|
|