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 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: "mcp",
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 = "mcp";
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 (backendType === "mcp") {
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/owner/repo
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/owner/juno-code#readme
24631
- Issues: https://github.com/owner/juno-code/issues
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
  `);