juno-code 1.0.38 → 1.0.40
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 +93 -0
- package/dist/bin/cli.js +54 -9
- package/dist/bin/cli.js.map +1 -1
- package/dist/bin/cli.mjs +54 -9
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/templates/scripts/__pycache__/github.cpython-38.pyc +0 -0
- package/dist/templates/scripts/github.py +2383 -0
- package/dist/templates/scripts/install_requirements.sh +270 -1
- package/dist/templates/scripts/kanban.sh +3 -1
- package/dist/templates/scripts/run_until_completion.sh +44 -4
- package/dist/templates/scripts/slack_respond.py +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -270,6 +270,99 @@ Then run with the hook:
|
|
|
270
270
|
./.juno_task/scripts/run_until_completion.sh --pre-run-hook SLACK_SYNC -s claude -i 5 -v
|
|
271
271
|
```
|
|
272
272
|
|
|
273
|
+
## GitHub Integration
|
|
274
|
+
|
|
275
|
+
juno-code includes built-in GitHub integration for issue tracking and automated responses. The system monitors GitHub repositories, creates kanban tasks from issues, and posts agent responses as threaded comments with automatic issue closure.
|
|
276
|
+
|
|
277
|
+
### How It Works
|
|
278
|
+
|
|
279
|
+
1. **Fetch**: `github.py fetch` monitors a GitHub repository and creates kanban tasks from new issues
|
|
280
|
+
2. **Process**: The AI agent processes tasks and records responses in the kanban
|
|
281
|
+
3. **Respond**: `github.py respond` posts agent responses as comments on GitHub issues and closes them
|
|
282
|
+
|
|
283
|
+
This enables a workflow where team members can submit tasks via GitHub issues and receive AI-generated responses with automatic issue closure.
|
|
284
|
+
|
|
285
|
+
### Setup
|
|
286
|
+
|
|
287
|
+
1. **Create a GitHub Personal Access Token**:
|
|
288
|
+
- Go to https://github.com/settings/tokens and create a new token (classic)
|
|
289
|
+
- Grant these permissions:
|
|
290
|
+
- `repo` (full control of private repositories)
|
|
291
|
+
- `public_repo` (access to public repositories)
|
|
292
|
+
- Copy the token (starts with `ghp_`)
|
|
293
|
+
|
|
294
|
+
2. **Configure Environment**:
|
|
295
|
+
```bash
|
|
296
|
+
# In project root .env file
|
|
297
|
+
GITHUB_TOKEN=ghp_your_token_here
|
|
298
|
+
GITHUB_REPO=owner/repo # Optional default repository
|
|
299
|
+
GITHUB_LABELS=bug,priority # Optional label filter
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
3. **Usage**:
|
|
303
|
+
```bash
|
|
304
|
+
# Fetch issues from GitHub and create tasks
|
|
305
|
+
./.juno_task/scripts/github.py fetch --repo owner/repo
|
|
306
|
+
|
|
307
|
+
# Filter by labels
|
|
308
|
+
./.juno_task/scripts/github.py fetch --repo owner/repo --labels bug,priority
|
|
309
|
+
|
|
310
|
+
# Post completed task responses back to GitHub
|
|
311
|
+
./.juno_task/scripts/github.py respond --tag github-issue
|
|
312
|
+
|
|
313
|
+
# Bidirectional sync (fetch + respond)
|
|
314
|
+
./.juno_task/scripts/github.py sync --repo owner/repo
|
|
315
|
+
|
|
316
|
+
# Continuous sync mode with interval
|
|
317
|
+
./.juno_task/scripts/github.py sync --repo owner/repo --continuous --interval 600
|
|
318
|
+
|
|
319
|
+
# One-time sync
|
|
320
|
+
./.juno_task/scripts/github.py sync --repo owner/repo --once
|
|
321
|
+
|
|
322
|
+
# Dry run to preview what would be posted
|
|
323
|
+
./.juno_task/scripts/github.py respond --dry-run --verbose
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Key Features
|
|
327
|
+
|
|
328
|
+
- **Tag-based identification**: Uses `github_issue_owner_repo_123` format for O(1) lookups
|
|
329
|
+
- **State tracking**: Maintains state in `.juno_task/github/state.ndjson` and `responses.ndjson`
|
|
330
|
+
- **Automatic closure**: Issues are automatically closed after posting the agent response
|
|
331
|
+
- **Commit linking**: Includes commit hash in comment if available
|
|
332
|
+
- **Response format**: Posts `agent_response` field from completed kanban tasks
|
|
333
|
+
|
|
334
|
+
### Automated GitHub Workflow with Hooks
|
|
335
|
+
|
|
336
|
+
Use the `--pre-run` flag to sync with GitHub before each juno-code run:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
# Fetch GitHub issues before starting work
|
|
340
|
+
./.juno_task/scripts/run_until_completion.sh \
|
|
341
|
+
--pre-run "./.juno_task/scripts/github.py fetch --repo owner/repo" \
|
|
342
|
+
-s claude -i 5 -v
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Or configure hooks in `.juno_task/config.json`:
|
|
346
|
+
|
|
347
|
+
```json
|
|
348
|
+
{
|
|
349
|
+
"hooks": {
|
|
350
|
+
"GITHUB_SYNC": {
|
|
351
|
+
"commands": [
|
|
352
|
+
"./.juno_task/scripts/github.py fetch --repo owner/repo --labels bug",
|
|
353
|
+
"./.juno_task/scripts/github.py respond --tag github-issue"
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Then run with the hook:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
./.juno_task/scripts/run_until_completion.sh --pre-run-hook GITHUB_SYNC -s claude -i 5 -v
|
|
364
|
+
```
|
|
365
|
+
|
|
273
366
|
## run_until_completion.sh
|
|
274
367
|
|
|
275
368
|
The `run_until_completion.sh` script continuously runs juno-code until all kanban tasks are completed. It uses a do-while loop pattern: juno-code runs at least once, then continues while tasks remain in backlog, todo, or in_progress status.
|
package/dist/bin/cli.js
CHANGED
|
@@ -1337,7 +1337,7 @@ var init_config = __esm({
|
|
|
1337
1337
|
DEFAULT_CONFIG = {
|
|
1338
1338
|
// Core settings
|
|
1339
1339
|
defaultSubagent: "claude",
|
|
1340
|
-
defaultBackend: "
|
|
1340
|
+
defaultBackend: "shell",
|
|
1341
1341
|
defaultMaxIterations: 50,
|
|
1342
1342
|
// Logging settings
|
|
1343
1343
|
logLevel: "info",
|
|
@@ -13426,8 +13426,11 @@ var init_script_installer = __esm({
|
|
|
13426
13426
|
// Wrapper script for Slack fetch
|
|
13427
13427
|
"slack_respond.py",
|
|
13428
13428
|
// Core logic for sending responses to Slack
|
|
13429
|
-
"slack_respond.sh"
|
|
13429
|
+
"slack_respond.sh",
|
|
13430
13430
|
// Wrapper script for Slack respond
|
|
13431
|
+
// GitHub integration script (single-file architecture)
|
|
13432
|
+
"github.py"
|
|
13433
|
+
// Unified GitHub integration (fetch, respond, sync)
|
|
13431
13434
|
];
|
|
13432
13435
|
/**
|
|
13433
13436
|
* Get the templates scripts directory from the package
|
|
@@ -14044,15 +14047,17 @@ async function validateStartupConfigs(baseDir = process.cwd(), verbose = false)
|
|
|
14044
14047
|
console.error(chalk15__default.default.blue("\u{1F50D} Validating JSON configuration files...\n"));
|
|
14045
14048
|
}
|
|
14046
14049
|
try {
|
|
14047
|
-
let backendType = "
|
|
14050
|
+
let backendType = "shell";
|
|
14051
|
+
let backendSetViaCliArg = false;
|
|
14048
14052
|
const backendArgIndex = process.argv.findIndex((arg) => arg === "-b" || arg === "--backend");
|
|
14049
14053
|
if (backendArgIndex !== -1 && process.argv[backendArgIndex + 1]) {
|
|
14050
14054
|
const cliBackend = process.argv[backendArgIndex + 1].toLowerCase().trim();
|
|
14051
14055
|
if (cliBackend === "shell" || cliBackend === "mcp") {
|
|
14052
14056
|
backendType = cliBackend;
|
|
14057
|
+
backendSetViaCliArg = true;
|
|
14053
14058
|
}
|
|
14054
14059
|
}
|
|
14055
|
-
if (
|
|
14060
|
+
if (!backendSetViaCliArg) {
|
|
14056
14061
|
const envBackend = process.env.JUNO_CODE_AGENT || process.env.JUNO_CODE_BACKEND || process.env.JUNO_TASK_BACKEND;
|
|
14057
14062
|
if (envBackend) {
|
|
14058
14063
|
const normalized = envBackend.toLowerCase().trim();
|
|
@@ -24307,7 +24312,7 @@ function handleCLIError(error, verbose = false) {
|
|
|
24307
24312
|
process.exit(EXIT_CODES.UNEXPECTED_ERROR);
|
|
24308
24313
|
}
|
|
24309
24314
|
function setupGlobalOptions(program) {
|
|
24310
|
-
program.option("-v, --verbose", "Enable verbose output with detailed progress").option("-q, --quiet", "Disable rich formatting, use plain text").option("-c, --config <path>", "Configuration file path (.json, .toml, pyproject.toml)").option("-l, --log-file <path>", "Log file path (auto-generated if not specified)").option("--no-color", "Disable colored output").option("--log-level <level>", "Log level for output (error, warn, info, debug, trace)", "info").option("-s, --subagent <name>", "Subagent to use (claude, cursor, codex, gemini)").option("-b, --backend <type>", "Backend to use (mcp, shell)").option("-m, --model <name>", "Model to use (subagent-specific)").option("--agents <config>", "Agents configuration (forwarded to shell backend, ignored for MCP)").option("--tools <tools...>", 'Specify the list of available tools from the built-in set (only works with --print mode). Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read"). Passed to shell backend, ignored for MCP.').option("--allowed-tools <tools...>", 'Permission-based filtering of specific tool instances (e.g. "Bash(git:*) Edit"). Default when not specified: Task, Bash, Glob, Grep, ExitPlanMode, Read, Edit, Write, NotebookEdit, WebFetch, TodoWrite, WebSearch, BashOutput, KillShell, Skill, SlashCommand, EnterPlanMode. Passed to shell backend, ignored for MCP.').option("--disallowed-tools <tools...>", "Disallowed tools for Claude (passed to shell backend, ignored for MCP). By default, no tools are disallowed").option("--append-allowed-tools <tools...>", "Append tools to the default allowed-tools list (mutually exclusive with --allowed-tools). Passed to shell backend, ignored for MCP.").option("--mcp-timeout <number>", "MCP server timeout in milliseconds", parseInt).option("--enable-feedback", "Enable interactive feedback mode (F+Enter to enter, Q+Enter to submit)").option("-r, --resume <sessionId>", "Resume a conversation by session ID (shell backend only)").option("--continue", "Continue the most recent conversation (shell backend only)");
|
|
24315
|
+
program.option("-v, --verbose", "Enable verbose output with detailed progress").option("-q, --quiet", "Disable rich formatting, use plain text").option("-c, --config <path>", "Configuration file path (.json, .toml, pyproject.toml)").option("-l, --log-file <path>", "Log file path (auto-generated if not specified)").option("--no-color", "Disable colored output").option("--log-level <level>", "Log level for output (error, warn, info, debug, trace)", "info").option("-s, --subagent <name>", "Subagent to use (claude, cursor, codex, gemini)").option("-b, --backend <type>", "Backend to use (mcp, shell) - default: shell").option("-m, --model <name>", "Model to use (subagent-specific)").option("--agents <config>", "Agents configuration (forwarded to shell backend, ignored for MCP)").option("--tools <tools...>", 'Specify the list of available tools from the built-in set (only works with --print mode). Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read"). Passed to shell backend, ignored for MCP.').option("--allowed-tools <tools...>", 'Permission-based filtering of specific tool instances (e.g. "Bash(git:*) Edit"). Default when not specified: Task, Bash, Glob, Grep, ExitPlanMode, Read, Edit, Write, NotebookEdit, WebFetch, TodoWrite, WebSearch, BashOutput, KillShell, Skill, SlashCommand, EnterPlanMode. Passed to shell backend, ignored for MCP.').option("--disallowed-tools <tools...>", "Disallowed tools for Claude (passed to shell backend, ignored for MCP). By default, no tools are disallowed").option("--append-allowed-tools <tools...>", "Append tools to the default allowed-tools list (mutually exclusive with --allowed-tools). Passed to shell backend, ignored for MCP.").option("--mcp-timeout <number>", "MCP server timeout in milliseconds", parseInt).option("--enable-feedback", "Enable interactive feedback mode (F+Enter to enter, Q+Enter to submit)").option("-r, --resume <sessionId>", "Resume a conversation by session ID (shell backend only)").option("--continue", "Continue the most recent conversation (shell backend only)").option("--til-completion", "Run juno-code in a loop until all kanban tasks are complete (aliases: --until-completion, --run-until-completion, --till-complete)").option("--until-completion", "Alias for --til-completion").addOption(new commander.Option("--run-until-completion", "Alias for --til-completion").hideHelp()).addOption(new commander.Option("--till-complete", "Alias for --til-completion").hideHelp()).option("--pre-run-hook <hooks...>", "Execute named hooks from .juno_task/config.json before each iteration (only with --til-completion)");
|
|
24311
24316
|
program.exitOverride((err) => {
|
|
24312
24317
|
if (err.code === "commander.helpDisplayed") {
|
|
24313
24318
|
process.exit(0);
|
|
@@ -24332,6 +24337,42 @@ function setupMainCommand(program) {
|
|
|
24332
24337
|
Object.entries(globalOptions).filter(([_, v]) => v !== void 0)
|
|
24333
24338
|
);
|
|
24334
24339
|
const allOptions2 = { ...definedGlobalOptions, ...options };
|
|
24340
|
+
if (allOptions2.tilCompletion || allOptions2.untilCompletion || allOptions2.runUntilCompletion || allOptions2.tillComplete) {
|
|
24341
|
+
const { spawn: spawn4 } = await import('child_process');
|
|
24342
|
+
const path24 = await import('path');
|
|
24343
|
+
const fs22 = await import('fs-extra');
|
|
24344
|
+
const scriptPath = path24.join(process.cwd(), ".juno_task", "scripts", "run_until_completion.sh");
|
|
24345
|
+
if (!await fs22.pathExists(scriptPath)) {
|
|
24346
|
+
console.error(chalk15__default.default.red.bold("\n\u274C Error: run_until_completion.sh not found"));
|
|
24347
|
+
console.error(chalk15__default.default.red(` Expected location: ${scriptPath}`));
|
|
24348
|
+
console.error(chalk15__default.default.yellow('\n\u{1F4A1} Suggestion: Run "juno-code init" to initialize the project'));
|
|
24349
|
+
process.exit(1);
|
|
24350
|
+
}
|
|
24351
|
+
const scriptArgs = [];
|
|
24352
|
+
if (allOptions2.preRunHook && Array.isArray(allOptions2.preRunHook)) {
|
|
24353
|
+
for (const hook of allOptions2.preRunHook) {
|
|
24354
|
+
scriptArgs.push("--pre-run-hook", hook);
|
|
24355
|
+
}
|
|
24356
|
+
}
|
|
24357
|
+
const completionFlags = ["--til-completion", "--until-completion", "--run-until-completion", "--till-complete"];
|
|
24358
|
+
const forwardedArgs = process.argv.slice(2).filter(
|
|
24359
|
+
(arg) => !completionFlags.includes(arg) && !arg.startsWith("--pre-run-hook")
|
|
24360
|
+
);
|
|
24361
|
+
scriptArgs.push(...forwardedArgs);
|
|
24362
|
+
const child = spawn4(scriptPath, scriptArgs, {
|
|
24363
|
+
stdio: "inherit",
|
|
24364
|
+
cwd: process.cwd()
|
|
24365
|
+
});
|
|
24366
|
+
child.on("exit", (code) => {
|
|
24367
|
+
process.exit(code || 0);
|
|
24368
|
+
});
|
|
24369
|
+
child.on("error", (error) => {
|
|
24370
|
+
console.error(chalk15__default.default.red.bold("\n\u274C Error executing run_until_completion.sh"));
|
|
24371
|
+
console.error(chalk15__default.default.red(` ${error.message}`));
|
|
24372
|
+
process.exit(1);
|
|
24373
|
+
});
|
|
24374
|
+
return;
|
|
24375
|
+
}
|
|
24335
24376
|
if (!globalOptions.subagent && !options.prompt && !options.interactive && !options.interactivePrompt) {
|
|
24336
24377
|
const fs22 = await import('fs-extra');
|
|
24337
24378
|
const path24 = await import('path');
|
|
@@ -24572,9 +24613,12 @@ ${chalk15__default.default.blue.bold("\u{1F3AF} Juno Code")} - TypeScript CLI fo
|
|
|
24572
24613
|
`);
|
|
24573
24614
|
program.addHelpText("afterAll", `
|
|
24574
24615
|
${chalk15__default.default.blue.bold("Examples:")}
|
|
24575
|
-
${chalk15__default.default.gray("# Initialize new project")}
|
|
24616
|
+
${chalk15__default.default.gray("# Initialize new project (interactive mode)")}
|
|
24576
24617
|
juno-code init
|
|
24577
24618
|
|
|
24619
|
+
${chalk15__default.default.gray("# Initialize with inline mode (automation-friendly)")}
|
|
24620
|
+
juno-code init "Build a REST API" --subagent claude --git-repo https://github.com/user/repo
|
|
24621
|
+
|
|
24578
24622
|
${chalk15__default.default.gray("# Start execution using .juno_task/init.md")}
|
|
24579
24623
|
juno-code start
|
|
24580
24624
|
|
|
@@ -24604,7 +24648,7 @@ ${chalk15__default.default.blue.bold("Examples:")}
|
|
|
24604
24648
|
juno-code config create development
|
|
24605
24649
|
|
|
24606
24650
|
${chalk15__default.default.gray("# Setup Git repository")}
|
|
24607
|
-
juno-code setup-git https://github.com/
|
|
24651
|
+
juno-code setup-git https://github.com/askbudi/juno-code
|
|
24608
24652
|
|
|
24609
24653
|
${chalk15__default.default.blue.bold("Environment Variables:")}
|
|
24610
24654
|
JUNO_CODE_SUBAGENT Default subagent (claude, cursor, codex, gemini)
|
|
@@ -24627,8 +24671,9 @@ ${chalk15__default.default.blue.bold("Configuration:")}
|
|
|
24627
24671
|
4. Built-in defaults (lowest priority)
|
|
24628
24672
|
|
|
24629
24673
|
${chalk15__default.default.blue.bold("Support:")}
|
|
24630
|
-
Documentation: https://github.com/
|
|
24631
|
-
Issues: https://github.com/
|
|
24674
|
+
Documentation: https://github.com/askbudi/juno-code#readme
|
|
24675
|
+
Issues: https://github.com/askbudi/juno-code/issues
|
|
24676
|
+
Website: https://askbudi.ai
|
|
24632
24677
|
License: MIT
|
|
24633
24678
|
|
|
24634
24679
|
`);
|