@bahulam/code 2.6.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 +80 -0
- package/package.json +49 -0
- package/pulse/app/activity/page.tsx +190 -0
- package/pulse/app/api/activity/route.ts +138 -0
- package/pulse/app/api/benchmark/route.ts +113 -0
- package/pulse/app/api/benchmarks/route.ts +195 -0
- package/pulse/app/api/costs/route.ts +88 -0
- package/pulse/app/api/export/route.ts +77 -0
- package/pulse/app/api/history/route.ts +11 -0
- package/pulse/app/api/import/route.ts +31 -0
- package/pulse/app/api/memory/route.ts +50 -0
- package/pulse/app/api/plans/route.ts +9 -0
- package/pulse/app/api/projects/[slug]/route.ts +96 -0
- package/pulse/app/api/projects/route.ts +121 -0
- package/pulse/app/api/sessions/[id]/replay/route.ts +20 -0
- package/pulse/app/api/sessions/[id]/route.ts +31 -0
- package/pulse/app/api/sessions/route.ts +112 -0
- package/pulse/app/api/settings/route.ts +14 -0
- package/pulse/app/api/stats/route.ts +143 -0
- package/pulse/app/api/todos/route.ts +9 -0
- package/pulse/app/api/tools/route.ts +160 -0
- package/pulse/app/benchmarks/page.tsx +224 -0
- package/pulse/app/costs/page.tsx +179 -0
- package/pulse/app/export/page.tsx +465 -0
- package/pulse/app/favicon.ico +0 -0
- package/pulse/app/globals.css +263 -0
- package/pulse/app/help/page.tsx +143 -0
- package/pulse/app/history/page.tsx +157 -0
- package/pulse/app/layout.tsx +46 -0
- package/pulse/app/memory/page.tsx +365 -0
- package/pulse/app/overview-client.tsx +393 -0
- package/pulse/app/page.tsx +14 -0
- package/pulse/app/plans/page.tsx +308 -0
- package/pulse/app/projects/[slug]/page.tsx +390 -0
- package/pulse/app/projects/page.tsx +110 -0
- package/pulse/app/sessions/[id]/page.tsx +243 -0
- package/pulse/app/sessions/page.tsx +39 -0
- package/pulse/app/settings/page.tsx +188 -0
- package/pulse/app/todos/page.tsx +211 -0
- package/pulse/app/tools/page.tsx +249 -0
- package/pulse/cli.js +164 -0
- package/pulse/components/activity/day-of-week-chart.tsx +35 -0
- package/pulse/components/activity/streak-card.tsx +36 -0
- package/pulse/components/costs/cache-efficiency-panel.tsx +76 -0
- package/pulse/components/costs/cost-by-project-chart.tsx +48 -0
- package/pulse/components/costs/cost-over-time-chart.tsx +95 -0
- package/pulse/components/costs/model-token-table.tsx +60 -0
- package/pulse/components/global-search.tsx +193 -0
- package/pulse/components/keyboard-nav-provider.tsx +23 -0
- package/pulse/components/layout/bottom-nav.tsx +53 -0
- package/pulse/components/layout/client-layout.tsx +31 -0
- package/pulse/components/layout/sidebar-context.tsx +50 -0
- package/pulse/components/layout/sidebar.tsx +183 -0
- package/pulse/components/layout/top-bar.tsx +121 -0
- package/pulse/components/overview/activity-heatmap.tsx +107 -0
- package/pulse/components/overview/conversation-table.tsx +148 -0
- package/pulse/components/overview/model-breakdown-donut.tsx +95 -0
- package/pulse/components/overview/peak-hours-chart.tsx +87 -0
- package/pulse/components/overview/project-activity-donut.tsx +96 -0
- package/pulse/components/overview/stat-card.tsx +102 -0
- package/pulse/components/overview/usage-over-time-chart.tsx +166 -0
- package/pulse/components/projects/project-card.tsx +175 -0
- package/pulse/components/sessions/replay/assistant-markdown.tsx +94 -0
- package/pulse/components/sessions/replay/compaction-card.tsx +25 -0
- package/pulse/components/sessions/replay/session-sidebar.tsx +231 -0
- package/pulse/components/sessions/replay/token-accumulation-chart.tsx +98 -0
- package/pulse/components/sessions/replay/tool-call-badge.tsx +127 -0
- package/pulse/components/sessions/replay/turn-cards.tsx +220 -0
- package/pulse/components/sessions/replay/user-tool-result.tsx +158 -0
- package/pulse/components/sessions/session-badges.tsx +49 -0
- package/pulse/components/sessions/session-table.tsx +299 -0
- package/pulse/components/theme-provider.tsx +44 -0
- package/pulse/components/tools/feature-adoption-table.tsx +58 -0
- package/pulse/components/tools/mcp-server-panel.tsx +45 -0
- package/pulse/components/tools/tool-ranking-chart.tsx +57 -0
- package/pulse/components/tools/version-history-table.tsx +32 -0
- package/pulse/components/ui/alert.tsx +66 -0
- package/pulse/components/ui/badge.tsx +48 -0
- package/pulse/components/ui/breadcrumb.tsx +109 -0
- package/pulse/components/ui/button.tsx +64 -0
- package/pulse/components/ui/calendar.tsx +220 -0
- package/pulse/components/ui/card.tsx +92 -0
- package/pulse/components/ui/command.tsx +158 -0
- package/pulse/components/ui/dialog.tsx +158 -0
- package/pulse/components/ui/input.tsx +21 -0
- package/pulse/components/ui/popover.tsx +89 -0
- package/pulse/components/ui/progress.tsx +31 -0
- package/pulse/components/ui/select.tsx +190 -0
- package/pulse/components/ui/separator.tsx +28 -0
- package/pulse/components/ui/sheet.tsx +143 -0
- package/pulse/components/ui/skeleton.tsx +13 -0
- package/pulse/components/ui/table.tsx +116 -0
- package/pulse/components/ui/tabs.tsx +91 -0
- package/pulse/components/ui/tooltip.tsx +57 -0
- package/pulse/components/use-global-keyboard-nav.ts +79 -0
- package/pulse/components.json +23 -0
- package/pulse/eslint.config.mjs +18 -0
- package/pulse/lib/bahulam-paths.ts +23 -0
- package/pulse/lib/claude-reader.ts +592 -0
- package/pulse/lib/decode.ts +129 -0
- package/pulse/lib/pricing.ts +102 -0
- package/pulse/lib/replay-parser.ts +165 -0
- package/pulse/lib/tool-categories.ts +127 -0
- package/pulse/lib/utils.ts +6 -0
- package/pulse/next-env.d.ts +6 -0
- package/pulse/next.config.ts +16 -0
- package/pulse/package.json +45 -0
- package/pulse/postcss.config.mjs +7 -0
- package/pulse/public/activity.png +0 -0
- package/pulse/public/cc-lens.png +0 -0
- package/pulse/public/command-k.png +0 -0
- package/pulse/public/costs.png +0 -0
- package/pulse/public/dashboard-dark.png +0 -0
- package/pulse/public/dashboard-white.png +0 -0
- package/pulse/public/export.png +0 -0
- package/pulse/public/file.svg +1 -0
- package/pulse/public/globe.svg +1 -0
- package/pulse/public/next.svg +1 -0
- package/pulse/public/projects.png +0 -0
- package/pulse/public/session-chat.png +0 -0
- package/pulse/public/todos.png +0 -0
- package/pulse/public/tools.png +0 -0
- package/pulse/public/vercel.svg +1 -0
- package/pulse/public/window.svg +1 -0
- package/pulse/tsconfig.json +34 -0
- package/pulse/types/claude.ts +294 -0
- package/src/agents/loader.mjs +94 -0
- package/src/agents/multi_workflow_loader.mjs +330 -0
- package/src/agents/parser.mjs +205 -0
- package/src/agents/scaffold.mjs +222 -0
- package/src/agents/teams.mjs +123 -0
- package/src/agents/workflow_loader.mjs +122 -0
- package/src/agents/workflow_scaffold.mjs +249 -0
- package/src/auth/oauth.mjs +220 -0
- package/src/auth/tarang-auth.mjs +306 -0
- package/src/commands/agent.mjs +220 -0
- package/src/commands/workflow.mjs +581 -0
- package/src/config/cli-args.mjs +200 -0
- package/src/config/env.mjs +263 -0
- package/src/config/hook-runner.mjs +100 -0
- package/src/config/memory-loader.mjs +32 -0
- package/src/config/settings-loader.mjs +45 -0
- package/src/config/settings.mjs +132 -0
- package/src/context/ast-parser.mjs +298 -0
- package/src/context/bm25.mjs +85 -0
- package/src/context/retriever.mjs +308 -0
- package/src/context/skeleton.mjs +134 -0
- package/src/context/symbol-indexer.mjs +375 -0
- package/src/core/agent-history.mjs +111 -0
- package/src/core/agent-loop.mjs +486 -0
- package/src/core/approval-log.mjs +104 -0
- package/src/core/approval.mjs +476 -0
- package/src/core/attachments.mjs +380 -0
- package/src/core/backend-url.mjs +55 -0
- package/src/core/cache-control.mjs +92 -0
- package/src/core/cache.mjs +105 -0
- package/src/core/callback-client.mjs +180 -0
- package/src/core/checkpoints.mjs +142 -0
- package/src/core/compact-history.mjs +127 -0
- package/src/core/context-envelope.mjs +54 -0
- package/src/core/context-manager.mjs +198 -0
- package/src/core/error-guidance.mjs +311 -0
- package/src/core/file-diff.mjs +217 -0
- package/src/core/headless.mjs +448 -0
- package/src/core/hooks-manager.mjs +87 -0
- package/src/core/jsonl-writer.mjs +449 -0
- package/src/core/local-agent.mjs +537 -0
- package/src/core/local-store.mjs +836 -0
- package/src/core/mode-selector.mjs +51 -0
- package/src/core/output-filter.mjs +177 -0
- package/src/core/paths.mjs +190 -0
- package/src/core/policy-resolver.mjs +156 -0
- package/src/core/pricing.mjs +336 -0
- package/src/core/project-artifacts.mjs +39 -0
- package/src/core/project-context-loader.mjs +139 -0
- package/src/core/providers.mjs +219 -0
- package/src/core/rate-limit-display.mjs +121 -0
- package/src/core/rate-limiter.mjs +119 -0
- package/src/core/resume-mode.mjs +192 -0
- package/src/core/risk-tier.mjs +337 -0
- package/src/core/safety.mjs +203 -0
- package/src/core/scheduler.mjs +173 -0
- package/src/core/session-manager.mjs +360 -0
- package/src/core/session.mjs +143 -0
- package/src/core/settings-sync.mjs +85 -0
- package/src/core/stagnation.mjs +57 -0
- package/src/core/stream-client.mjs +829 -0
- package/src/core/streaming.mjs +182 -0
- package/src/core/system-prompt.mjs +140 -0
- package/src/core/tasks.mjs +196 -0
- package/src/core/tool-executor.mjs +1950 -0
- package/src/core/trust.mjs +158 -0
- package/src/core/work-scope.mjs +248 -0
- package/src/hooks/engine.mjs +162 -0
- package/src/index.mjs +426 -0
- package/src/mcp/client.mjs +253 -0
- package/src/mcp/transport-shttp.mjs +130 -0
- package/src/mcp/transport-sse.mjs +131 -0
- package/src/mcp/transport-ws.mjs +134 -0
- package/src/onboarding/preflight.mjs +360 -0
- package/src/permissions/checker.mjs +57 -0
- package/src/permissions/command-classifier.mjs +652 -0
- package/src/permissions/injection-check.mjs +60 -0
- package/src/permissions/path-check.mjs +102 -0
- package/src/permissions/prompt.mjs +73 -0
- package/src/permissions/sandbox.mjs +112 -0
- package/src/plugins/loader.mjs +138 -0
- package/src/skills/installer.mjs +188 -0
- package/src/skills/loader.mjs +252 -0
- package/src/skills/runner.mjs +55 -0
- package/src/state/orbit.mjs +263 -0
- package/src/state/verbosity.mjs +99 -0
- package/src/telemetry/index.mjs +96 -0
- package/src/terminal/agents.mjs +177 -0
- package/src/terminal/analytics.mjs +292 -0
- package/src/terminal/ansi.mjs +695 -0
- package/src/terminal/init.mjs +145 -0
- package/src/terminal/main.mjs +269 -0
- package/src/terminal/repl-explore.mjs +35 -0
- package/src/terminal/repl-format.mjs +257 -0
- package/src/terminal/repl-render.mjs +561 -0
- package/src/terminal/repl-resume.mjs +625 -0
- package/src/terminal/repl-state.mjs +103 -0
- package/src/terminal/repl-utils.mjs +34 -0
- package/src/terminal/repl.mjs +3832 -0
- package/src/terminal/skills.mjs +54 -0
- package/src/terminal/tool-display.mjs +240 -0
- package/src/tools/agent.mjs +137 -0
- package/src/tools/ask-user.mjs +61 -0
- package/src/tools/bash.mjs +231 -0
- package/src/tools/cron-create.mjs +120 -0
- package/src/tools/cron-delete.mjs +49 -0
- package/src/tools/cron-list.mjs +37 -0
- package/src/tools/edit.mjs +82 -0
- package/src/tools/enter-worktree.mjs +69 -0
- package/src/tools/exit-worktree.mjs +57 -0
- package/src/tools/glob.mjs +117 -0
- package/src/tools/grep.mjs +129 -0
- package/src/tools/lint.mjs +71 -0
- package/src/tools/ls.mjs +58 -0
- package/src/tools/lsp.mjs +115 -0
- package/src/tools/multi-edit.mjs +94 -0
- package/src/tools/notebook-edit.mjs +96 -0
- package/src/tools/project-overview.mjs +641 -0
- package/src/tools/read-mcp-resource.mjs +57 -0
- package/src/tools/read.mjs +138 -0
- package/src/tools/registry.mjs +116 -0
- package/src/tools/remote-trigger.mjs +84 -0
- package/src/tools/send-message.mjs +64 -0
- package/src/tools/skill.mjs +52 -0
- package/src/tools/test-runner.mjs +49 -0
- package/src/tools/todo-write.mjs +68 -0
- package/src/tools/tool-search.mjs +77 -0
- package/src/tools/web-fetch.mjs +65 -0
- package/src/tools/web-search.mjs +89 -0
- package/src/tools/write.mjs +55 -0
- package/src/ui/approval.mjs +263 -0
- package/src/ui/banner.mjs +235 -0
- package/src/ui/commands.mjs +537 -0
- package/src/ui/formatter.mjs +409 -0
- package/src/ui/icons.mjs +164 -0
- package/src/ui/input-dock.mjs +444 -0
- package/src/ui/markdown.mjs +278 -0
- package/src/ui/mission-report.mjs +296 -0
- package/src/ui/palette.mjs +189 -0
- package/src/ui/slash-commands.mjs +245 -0
- package/src/ui/spinner.mjs +116 -0
- package/src/ui/sub-agent.mjs +152 -0
- package/src/ui/term.mjs +159 -0
- package/src/ui/text-layout.mjs +127 -0
- package/src/ui/tool-card.mjs +463 -0
- package/src/ui/tool-details.mjs +312 -0
- package/src/ui/transcript-block.mjs +21 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const FILES = {
|
|
5
|
+
'README.md': `# .bahulam/ - project agent context
|
|
6
|
+
|
|
7
|
+
Bahulam Code reads and writes here to keep state between sessions.
|
|
8
|
+
|
|
9
|
+
## Files Bahulam Code writes
|
|
10
|
+
- \`plan.md\` - current agent plan
|
|
11
|
+
- \`goal.md\` - durable session goal
|
|
12
|
+
- \`tasks/\` - task list
|
|
13
|
+
- \`reports/*.md\` - end-of-turn mission reports
|
|
14
|
+
- \`sessions/*.jsonl\` - turn transcripts
|
|
15
|
+
- \`commands.log\` - command executions
|
|
16
|
+
- \`approvals.log\` - HITL decisions
|
|
17
|
+
- \`trust.json\` - approved patterns
|
|
18
|
+
|
|
19
|
+
## Files you can write
|
|
20
|
+
- \`config.json\` - project policy
|
|
21
|
+
- \`project.md\` - durable project context
|
|
22
|
+
- \`style.md\` - codebase conventions
|
|
23
|
+
- \`hitl.md\` - approval guidance
|
|
24
|
+
- \`skills/<name>/SKILL.md\` - reusable domain skills
|
|
25
|
+
|
|
26
|
+
Format v1. Markdown files are intentionally hand-editable.
|
|
27
|
+
`,
|
|
28
|
+
'config.json': JSON.stringify({
|
|
29
|
+
version: 1,
|
|
30
|
+
context: {
|
|
31
|
+
loadEveryTurn: ['KEPLER.md', 'project.md', 'style.md', 'goal.md', 'plan.md', 'tasks/*.md'],
|
|
32
|
+
showReloadNotice: true,
|
|
33
|
+
},
|
|
34
|
+
planning: { owner: 'auto', onUserEditedPlan: 'prefer_user_plan' },
|
|
35
|
+
tasks: { storage: 'project_markdown', syncTodoWrite: true, resumePrompt: true },
|
|
36
|
+
hitl: {
|
|
37
|
+
defaultScope: 'once',
|
|
38
|
+
allowSessionTrust: true,
|
|
39
|
+
allowProjectTrust: false,
|
|
40
|
+
reaskAfterMinutes: 30,
|
|
41
|
+
},
|
|
42
|
+
commands: {
|
|
43
|
+
enabled: ['map', 'probe', 'footprint', 'heal', 'align', 'distill', 'brief', 'rewind'],
|
|
44
|
+
dryRunDefault: false,
|
|
45
|
+
},
|
|
46
|
+
}, null, 2) + '\n',
|
|
47
|
+
'settings.json': JSON.stringify({
|
|
48
|
+
env: {},
|
|
49
|
+
permissions: {
|
|
50
|
+
shellAllowlist: ['git', 'npm', 'pnpm'],
|
|
51
|
+
editDenylist: ['**/*.env', 'secrets/**'],
|
|
52
|
+
},
|
|
53
|
+
hooks: {
|
|
54
|
+
UserPromptSubmit: [],
|
|
55
|
+
PreToolUse: [],
|
|
56
|
+
PostToolUse: [],
|
|
57
|
+
Stop: [],
|
|
58
|
+
},
|
|
59
|
+
}, null, 2) + '\n',
|
|
60
|
+
'KEPLER.md': `# Project
|
|
61
|
+
|
|
62
|
+
## Quick Facts
|
|
63
|
+
- Stack:
|
|
64
|
+
- Test command:
|
|
65
|
+
- Lint command:
|
|
66
|
+
- Build command:
|
|
67
|
+
|
|
68
|
+
## Key Directories
|
|
69
|
+
|
|
70
|
+
## Code Style
|
|
71
|
+
|
|
72
|
+
## Critical Rules
|
|
73
|
+
`,
|
|
74
|
+
'project.md': '# Project Context\n\nAdd durable project context here.\n',
|
|
75
|
+
'style.md': '# Style\n\nAdd code and communication conventions here.\n',
|
|
76
|
+
'hitl.md': '# HITL Guidance\n\nAdd project-specific approval guidance here.\n',
|
|
77
|
+
'trust.json': JSON.stringify({ version: 1, rules: [] }, null, 2) + '\n',
|
|
78
|
+
'tasks/README.md': `# Bahulam Tasks
|
|
79
|
+
|
|
80
|
+
Checklist files are read every turn.
|
|
81
|
+
|
|
82
|
+
- \`backlog.md\` - pending tasks
|
|
83
|
+
- \`active.md\` - current task
|
|
84
|
+
- \`done.md\` - completed tasks
|
|
85
|
+
- \`blocked.md\` - waiting on input
|
|
86
|
+
`,
|
|
87
|
+
'tasks/backlog.md': '# Backlog\n\n',
|
|
88
|
+
'tasks/active.md': '# Active\n\n',
|
|
89
|
+
'tasks/done.md': '# Done\n\n',
|
|
90
|
+
'tasks/blocked.md': '# Blocked\n\n',
|
|
91
|
+
'skills/starter/SKILL.md': `---
|
|
92
|
+
name: starter
|
|
93
|
+
description: Project-specific conventions and setup notes. Use when onboarding to this repo.
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
# Starter Skill
|
|
97
|
+
|
|
98
|
+
Add reusable project knowledge here.
|
|
99
|
+
`,
|
|
100
|
+
'commands/onboard.md': `---
|
|
101
|
+
name: onboard
|
|
102
|
+
description: Explore the project and record onboarding notes.
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
# Onboard
|
|
106
|
+
|
|
107
|
+
Context:
|
|
108
|
+
$ARGUMENTS
|
|
109
|
+
|
|
110
|
+
Explore the codebase, ask clarifying questions, and record useful notes in .bahulam/tasks/active.md.
|
|
111
|
+
`,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export function scaffoldKeplerProject({ cwd = process.cwd(), force = false } = {}) {
|
|
115
|
+
const root = path.join(cwd, '.bahulam');
|
|
116
|
+
const written = [];
|
|
117
|
+
const skipped = [];
|
|
118
|
+
for (const [rel, content] of Object.entries(FILES)) {
|
|
119
|
+
const filePath = path.join(root, rel);
|
|
120
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
121
|
+
if (fs.existsSync(filePath) && !force) {
|
|
122
|
+
skipped.push(filePath);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
fs.writeFileSync(filePath, content);
|
|
126
|
+
written.push(filePath);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const gitignore = path.join(root, '.gitignore');
|
|
130
|
+
if (!fs.existsSync(gitignore) || force) {
|
|
131
|
+
fs.writeFileSync(gitignore, 'settings.local.json\nsessions/\nreports/\n*.log\n');
|
|
132
|
+
written.push(gitignore);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { root, written, skipped };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function runInitCommand(args = [], { cwd = process.cwd() } = {}) {
|
|
139
|
+
const force = args.includes('--force');
|
|
140
|
+
const result = scaffoldKeplerProject({ cwd, force });
|
|
141
|
+
process.stderr.write(`\x1b[32m✓\x1b[0m Initialized .bahulam at ${result.root}\n`);
|
|
142
|
+
process.stderr.write(` wrote ${result.written.length} files`);
|
|
143
|
+
if (result.skipped.length) process.stderr.write(`, skipped ${result.skipped.length} existing files`);
|
|
144
|
+
process.stderr.write('\n');
|
|
145
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Bahulam Code CLI — ANSI Terminal UI. Bahulam's coding agent.
|
|
4
|
+
* Zero React. Zero Ink. Zero flickering.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { startTerminalRepl } from './repl.mjs';
|
|
8
|
+
import {
|
|
9
|
+
runSessionsCommand,
|
|
10
|
+
runStatsCommand,
|
|
11
|
+
runHistoryCommand,
|
|
12
|
+
} from './analytics.mjs';
|
|
13
|
+
import { parseArgs } from '../config/cli-args.mjs';
|
|
14
|
+
|
|
15
|
+
// ── Subcommands ──
|
|
16
|
+
|
|
17
|
+
const subcommand = process.argv[2];
|
|
18
|
+
const subcommandArgs = process.argv.slice(3);
|
|
19
|
+
|
|
20
|
+
function parseKeplerSubcommandArgs(command, argv) {
|
|
21
|
+
const parsed = {
|
|
22
|
+
command,
|
|
23
|
+
workflowSubcommand: null,
|
|
24
|
+
workflowSlug: null,
|
|
25
|
+
workflowFile: null,
|
|
26
|
+
workflowDir: null,
|
|
27
|
+
agentSubcommand: null,
|
|
28
|
+
agentSlug: null,
|
|
29
|
+
agentDir: null,
|
|
30
|
+
instruction: null,
|
|
31
|
+
pattern: null,
|
|
32
|
+
yes: false,
|
|
33
|
+
verbose: false,
|
|
34
|
+
debug: false,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < argv.length; i++) {
|
|
38
|
+
const arg = argv[i];
|
|
39
|
+
switch (arg) {
|
|
40
|
+
case '--file':
|
|
41
|
+
case '-f':
|
|
42
|
+
parsed.workflowFile = argv[++i];
|
|
43
|
+
break;
|
|
44
|
+
case '--dir':
|
|
45
|
+
if (command === 'agent') parsed.agentDir = argv[++i];
|
|
46
|
+
else parsed.workflowDir = argv[++i];
|
|
47
|
+
break;
|
|
48
|
+
case '--instruction':
|
|
49
|
+
case '--input':
|
|
50
|
+
case '--print':
|
|
51
|
+
case '-p':
|
|
52
|
+
parsed.instruction = argv[++i];
|
|
53
|
+
break;
|
|
54
|
+
case '--pattern':
|
|
55
|
+
parsed.pattern = argv[++i];
|
|
56
|
+
break;
|
|
57
|
+
case '--yes':
|
|
58
|
+
case '-y':
|
|
59
|
+
parsed.yes = true;
|
|
60
|
+
break;
|
|
61
|
+
case '--verbose':
|
|
62
|
+
case '-v':
|
|
63
|
+
parsed.verbose = true;
|
|
64
|
+
break;
|
|
65
|
+
case '--debug':
|
|
66
|
+
case '-d':
|
|
67
|
+
parsed.debug = true;
|
|
68
|
+
parsed.verbose = true;
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
if (arg.startsWith('-')) break;
|
|
72
|
+
if (command === 'workflow') {
|
|
73
|
+
if (!parsed.workflowSubcommand) parsed.workflowSubcommand = arg;
|
|
74
|
+
else if (!parsed.workflowSlug) parsed.workflowSlug = arg;
|
|
75
|
+
} else if (command === 'agent') {
|
|
76
|
+
if (!parsed.agentSubcommand) parsed.agentSubcommand = arg;
|
|
77
|
+
else if (!parsed.agentSlug) parsed.agentSlug = arg;
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return parsed;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function main() {
|
|
87
|
+
if (subcommand === 'dashboard') {
|
|
88
|
+
// Launch Bahulam Pulse Next.js dashboard
|
|
89
|
+
const { spawn } = await import('node:child_process');
|
|
90
|
+
const { fileURLToPath } = await import('node:url');
|
|
91
|
+
const path = await import('node:path');
|
|
92
|
+
const cliPath = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'pulse', 'cli.js');
|
|
93
|
+
const child = spawn(process.execPath, [cliPath, ...subcommandArgs], {
|
|
94
|
+
stdio: 'inherit',
|
|
95
|
+
env: process.env,
|
|
96
|
+
});
|
|
97
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (subcommand === 'sessions') {
|
|
102
|
+
await runSessionsCommand(subcommandArgs);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (subcommand === 'stats') {
|
|
107
|
+
await runStatsCommand(subcommandArgs);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (subcommand === 'history') {
|
|
112
|
+
await runHistoryCommand(subcommandArgs);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (subcommand === 'init') {
|
|
117
|
+
const { runInitCommand } = await import('./init.mjs');
|
|
118
|
+
await runInitCommand(subcommandArgs);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (subcommand === 'skills' || subcommand === 'skill') {
|
|
123
|
+
const { runSkillsCommand } = await import('./skills.mjs');
|
|
124
|
+
try {
|
|
125
|
+
await runSkillsCommand(subcommandArgs);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
process.stderr.write(`\x1b[31m✗ Skills command failed: ${err.message}\x1b[0m\n`);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (subcommand === 'login') {
|
|
134
|
+
const { TarangAuth } = await import('../auth/tarang-auth.mjs');
|
|
135
|
+
const auth = new TarangAuth();
|
|
136
|
+
try {
|
|
137
|
+
await auth.login();
|
|
138
|
+
process.stderr.write('\x1b[32m✓ Login successful!\x1b[0m\n');
|
|
139
|
+
return;
|
|
140
|
+
} catch (err) {
|
|
141
|
+
process.stderr.write(`\x1b[31m✗ Login failed: ${err.message}\x1b[0m\n`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (subcommand === 'logout') {
|
|
147
|
+
const { TarangAuth } = await import('../auth/tarang-auth.mjs');
|
|
148
|
+
const auth = new TarangAuth();
|
|
149
|
+
const success = auth.logout();
|
|
150
|
+
if (success) {
|
|
151
|
+
process.stderr.write('\x1b[32m✓ Signed out. Credentials cleared.\x1b[0m\n');
|
|
152
|
+
} else {
|
|
153
|
+
process.stderr.write('\x1b[33m! No credentials to clear.\x1b[0m\n');
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (subcommand === 'workflow') {
|
|
159
|
+
const { handleWorkflowCommand } = await import('../commands/workflow.mjs');
|
|
160
|
+
await handleWorkflowCommand(parseKeplerSubcommandArgs('workflow', subcommandArgs));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (subcommand === 'agent') {
|
|
165
|
+
const { handleAgentCommand } = await import('../commands/agent.mjs');
|
|
166
|
+
await handleAgentCommand(parseKeplerSubcommandArgs('agent', subcommandArgs));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (subcommand === 'version' || subcommand === '--version' || subcommand === '-v') {
|
|
171
|
+
const { createRequire } = await import('node:module');
|
|
172
|
+
const require = createRequire(import.meta.url);
|
|
173
|
+
const { version } = require('../../package.json');
|
|
174
|
+
process.stdout.write(`Bahulam Code v${version}\n`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
|
|
179
|
+
process.stderr.write(`
|
|
180
|
+
\x1b[1m\x1b[36mBahulam Code\x1b[0m — Bahulam's coding agent — bahulam.ai
|
|
181
|
+
|
|
182
|
+
\x1b[1mUsage:\x1b[0m
|
|
183
|
+
bahulam-code Start interactive REPL
|
|
184
|
+
bahulam-code "instruction" Run a single instruction
|
|
185
|
+
bahulam-code --headless -p "x" Non-interactive: auto-approve, JSONL output
|
|
186
|
+
bahulam-code --headless -p "x" --vision screenshot.png
|
|
187
|
+
Attach an image via the vision analysis pipeline
|
|
188
|
+
bahulam-code --resume Resume last conversation
|
|
189
|
+
bahulam-code dashboard Open analytics dashboard
|
|
190
|
+
bahulam-code login Sign in via browser
|
|
191
|
+
bahulam-code logout Sign out and clear credentials
|
|
192
|
+
bahulam-code init Scaffold .bahulam config, memory, hooks, tasks
|
|
193
|
+
bahulam-code version Show version
|
|
194
|
+
|
|
195
|
+
\x1b[1mAnalytics:\x1b[0m
|
|
196
|
+
bahulam-code sessions List recent local sessions
|
|
197
|
+
bahulam-code stats Show aggregate local session stats
|
|
198
|
+
bahulam-code history Show recent prompt history
|
|
199
|
+
|
|
200
|
+
\x1b[1mSkills:\x1b[0m
|
|
201
|
+
bahulam-code skills list [--all|--project]
|
|
202
|
+
bahulam-code skills view <name> [resource]
|
|
203
|
+
bahulam-code skills install <path-or-git-url> [--project] [--force]
|
|
204
|
+
bahulam-code skills update <name> [--project]
|
|
205
|
+
bahulam-code skills remove <name> [--project]
|
|
206
|
+
|
|
207
|
+
\x1b[1mREPL Commands:\x1b[0m
|
|
208
|
+
/help Show available commands
|
|
209
|
+
/stats Session metrics (tokens, cost, tools)
|
|
210
|
+
/cost Detailed cost breakdown by model
|
|
211
|
+
/model [role] [model] Show or set session model override
|
|
212
|
+
/history Conversation history
|
|
213
|
+
/new Start a new session
|
|
214
|
+
/clear Clear conversation history
|
|
215
|
+
/safety Show safety guardrail status
|
|
216
|
+
/revoke Revoke auto-approvals
|
|
217
|
+
/explore <query> Spawn read-only codebase explorer
|
|
218
|
+
/review <query> Spawn code review agent
|
|
219
|
+
/architect <query> Spawn architecture planning agent
|
|
220
|
+
/agents create <name> Create project-local user-defined agent YAML
|
|
221
|
+
/agents edit <name> Open a local agent YAML in your editor
|
|
222
|
+
/agents sync [name] Sync all or one local agent to Supabase
|
|
223
|
+
/attach <image-path> Attach an image to next prompt
|
|
224
|
+
/attach clipboard Attach image copied to macOS/Windows clipboard
|
|
225
|
+
/exit Exit the REPL
|
|
226
|
+
|
|
227
|
+
\x1b[1mKeyboard:\x1b[0m
|
|
228
|
+
Esc Cancel current execution
|
|
229
|
+
Space Pause / resume execution
|
|
230
|
+
Ctrl+C Exit
|
|
231
|
+
|
|
232
|
+
\x1b[1mEnvironment:\x1b[0m
|
|
233
|
+
TARANG_ENV Set backend (local, treetop, production)
|
|
234
|
+
ANTHROPIC_API_KEY Direct Anthropic API key
|
|
235
|
+
OPENROUTER_API_KEY OpenRouter API key
|
|
236
|
+
BAHULAM_CONFIG_DIR Override config directory (default: ~/.bahulam)
|
|
237
|
+
KEPLER_CONFIG_DIR Legacy config directory override
|
|
238
|
+
KEPLER_RECONNECT_MAX_ELAPSED_MS
|
|
239
|
+
Max reconnect window for dropped streams
|
|
240
|
+
KEPLER_BLOCK_SEPARATOR Tool/content separator: space, dotted, or off
|
|
241
|
+
|
|
242
|
+
\x1b[2mDocs: https://0xb0.ai\x1b[0m
|
|
243
|
+
`);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ── Headless mode (benchmarks, automation) ──
|
|
248
|
+
const args = parseArgs(process.argv.slice(2));
|
|
249
|
+
if (args.prompt && (process.argv.includes('--headless') || !process.stdin.isTTY)) {
|
|
250
|
+
const { runHeadless } = await import('../core/headless.mjs');
|
|
251
|
+
await runHeadless({
|
|
252
|
+
instruction: args.prompt,
|
|
253
|
+
model: args.model,
|
|
254
|
+
timeout: args.timeout || (args.maxTurns ? args.maxTurns * 60 : 600),
|
|
255
|
+
verbose: args.verbose,
|
|
256
|
+
cacheReport: args.cacheReport,
|
|
257
|
+
local: args.local,
|
|
258
|
+
vision: args.vision,
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
await startTerminalRepl();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
main().catch(err => {
|
|
267
|
+
process.stderr.write(`\x1b[31mFatal: ${err.message}\x1b[0m\n`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explore-run classifier — pure category lookup for the read/list/search/index
|
|
3
|
+
* tool bursts that get collapsed into one animated summary line during a
|
|
4
|
+
* sub-agent run.
|
|
5
|
+
*
|
|
6
|
+
* These functions are stateless. The mutable run state (counts, recent
|
|
7
|
+
* paths, lineActive flag) still lives in repl.mjs during the split.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const EXPLORE_TOOL_CATEGORY = new Map([
|
|
11
|
+
['read_file', 'read'], ['read', 'read'], ['read_files', 'read'],
|
|
12
|
+
['read_batch', 'read'], ['get_file_info', 'read'],
|
|
13
|
+
['list_files', 'list'], ['glob', 'list'], ['ls', 'list'],
|
|
14
|
+
['search_code', 'search'], ['search_files', 'search'], ['grep', 'search'],
|
|
15
|
+
['index_project', 'index'], ['register_project', 'index'],
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
export function exploreCollapseEnabled() {
|
|
19
|
+
return process.env.KEPLER_EXPLORE_COLLAPSE !== '0';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isExploreTool(tool) {
|
|
23
|
+
if (!exploreCollapseEnabled()) return false;
|
|
24
|
+
return EXPLORE_TOOL_CATEGORY.has(String(tool || '').toLowerCase());
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function exploreCategory(tool) {
|
|
28
|
+
return EXPLORE_TOOL_CATEGORY.get(String(tool || '').toLowerCase()) || 'explore';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Test-only accessor so unit tests can enumerate the recognized tools
|
|
32
|
+
// without importing the private Map.
|
|
33
|
+
export function _knownExploreTools() {
|
|
34
|
+
return [...EXPLORE_TOOL_CATEGORY.keys()];
|
|
35
|
+
}
|