@bike4mind/cli 0.2.11-ja-fix-confluence-table-data-5752.17346 → 0.2.11

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.
@@ -36,16 +36,24 @@ const argv = yargs(hideBin(process.argv))
36
36
  description: 'Show debug logs in console',
37
37
  default: false,
38
38
  })
39
+ .option('no-project-config', {
40
+ type: 'boolean',
41
+ description: 'Disable loading project-specific configuration (.bike4mind/)',
42
+ default: false,
43
+ })
39
44
  .help()
40
45
  .alias('help', 'h')
41
46
  .version()
42
47
  .alias('version', 'V')
43
48
  .parse();
44
49
 
45
- // Set environment variable for verbose mode
50
+ // Set environment variables from CLI flags
46
51
  if (argv.verbose) {
47
52
  process.env.B4M_VERBOSE = '1';
48
53
  }
54
+ if (argv['no-project-config']) {
55
+ process.env.B4M_NO_PROJECT_CONFIG = '1';
56
+ }
49
57
 
50
58
  // Auto-detect environment: prefer production mode when dist exists
51
59
  const distPath = join(__dirname, '../dist/index.js');
File without changes
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-FQDYYJMI.js";
4
+ } from "./chunk-OHR7UCTC.js";
5
5
  import "./chunk-PDX44BCA.js";
6
6
 
7
7
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
File without changes
File without changes
File without changes
@@ -16,7 +16,7 @@ import {
16
16
  dayjsConfig_default,
17
17
  extractSnippetMeta,
18
18
  settingsMap
19
- } from "./chunk-FQDYYJMI.js";
19
+ } from "./chunk-OHR7UCTC.js";
20
20
 
21
21
  // ../../b4m-core/packages/utils/dist/src/storage/S3Storage.js
22
22
  import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
@@ -6267,6 +6267,8 @@ var ensureToolPairingIntegrity = (messages, logger) => {
6267
6267
  return messages;
6268
6268
  }
6269
6269
  const toolUseIds = /* @__PURE__ */ new Set();
6270
+ const toolResultIds = /* @__PURE__ */ new Set();
6271
+ let hasToolUseBlocks = false;
6270
6272
  let hasToolResultBlocks = false;
6271
6273
  for (let i = 0; i < messages.length; i++) {
6272
6274
  const message = messages[i];
@@ -6276,65 +6278,111 @@ var ensureToolPairingIntegrity = (messages, logger) => {
6276
6278
  const block = content[j];
6277
6279
  if (block.type === "tool_use" && "id" in block) {
6278
6280
  toolUseIds.add(block.id);
6281
+ hasToolUseBlocks = true;
6279
6282
  }
6280
6283
  }
6281
6284
  } else if (message.role === "user" && Array.isArray(message.content)) {
6282
6285
  const content = message.content;
6283
6286
  for (let j = 0; j < content.length; j++) {
6284
- if (content[j].type === "tool_result") {
6287
+ const block = content[j];
6288
+ if (block.type === "tool_result" && "tool_use_id" in block) {
6289
+ toolResultIds.add(block.tool_use_id);
6285
6290
  hasToolResultBlocks = true;
6286
- break;
6287
6291
  }
6288
6292
  }
6289
6293
  }
6290
6294
  }
6291
- if (!hasToolResultBlocks) {
6295
+ if (!hasToolUseBlocks && !hasToolResultBlocks) {
6292
6296
  return messages;
6293
6297
  }
6294
- let orphanedCount = 0;
6298
+ let orphanedToolResultCount = 0;
6299
+ let orphanedToolUseCount = 0;
6295
6300
  const result = [];
6296
6301
  for (let i = 0; i < messages.length; i++) {
6297
6302
  const message = messages[i];
6298
- if (message.role !== "user" || !Array.isArray(message.content)) {
6299
- result.push(message);
6300
- continue;
6301
- }
6302
- const content = message.content;
6303
- let hasOrphans = false;
6304
- for (let j = 0; j < content.length; j++) {
6305
- const block = content[j];
6306
- if (block.type === "tool_result" && "tool_use_id" in block) {
6307
- if (!toolUseIds.has(block.tool_use_id)) {
6308
- hasOrphans = true;
6309
- break;
6303
+ if (message.role === "assistant" && Array.isArray(message.content)) {
6304
+ const content = message.content;
6305
+ let hasOrphanedToolUse = false;
6306
+ for (let j = 0; j < content.length; j++) {
6307
+ const block = content[j];
6308
+ if (block.type === "tool_use" && "id" in block) {
6309
+ if (!toolResultIds.has(block.id)) {
6310
+ hasOrphanedToolUse = true;
6311
+ break;
6312
+ }
6310
6313
  }
6311
6314
  }
6312
- }
6313
- if (!hasOrphans) {
6314
- result.push(message);
6315
+ if (!hasOrphanedToolUse) {
6316
+ result.push(message);
6317
+ continue;
6318
+ }
6319
+ const filteredContent = [];
6320
+ for (let j = 0; j < content.length; j++) {
6321
+ const block = content[j];
6322
+ if (block.type === "tool_use" && "id" in block) {
6323
+ const toolId = block.id;
6324
+ if (!toolResultIds.has(toolId)) {
6325
+ orphanedToolUseCount++;
6326
+ if (logger) {
6327
+ logger.warn(`Removing orphaned tool_use block with id: ${toolId} (no matching tool_result)`);
6328
+ }
6329
+ continue;
6330
+ }
6331
+ }
6332
+ filteredContent.push(block);
6333
+ }
6334
+ if (filteredContent.length > 0) {
6335
+ result.push({ ...message, content: filteredContent });
6336
+ }
6315
6337
  continue;
6316
6338
  }
6317
- const filteredContent = [];
6318
- for (let j = 0; j < content.length; j++) {
6319
- const block = content[j];
6320
- if (block.type === "tool_result" && "tool_use_id" in block) {
6321
- const toolUseId = block.tool_use_id;
6322
- if (!toolUseIds.has(toolUseId)) {
6323
- orphanedCount++;
6324
- if (logger) {
6325
- logger.warn(`Removing orphaned tool_result block referencing missing tool_use_id: ${toolUseId}`);
6339
+ if (message.role === "user" && Array.isArray(message.content)) {
6340
+ const content = message.content;
6341
+ let hasOrphanedToolResult = false;
6342
+ for (let j = 0; j < content.length; j++) {
6343
+ const block = content[j];
6344
+ if (block.type === "tool_result" && "tool_use_id" in block) {
6345
+ if (!toolUseIds.has(block.tool_use_id)) {
6346
+ hasOrphanedToolResult = true;
6347
+ break;
6326
6348
  }
6327
- continue;
6328
6349
  }
6329
6350
  }
6330
- filteredContent.push(block);
6331
- }
6332
- if (filteredContent.length > 0) {
6333
- result.push({ ...message, content: filteredContent });
6351
+ if (!hasOrphanedToolResult) {
6352
+ result.push(message);
6353
+ continue;
6354
+ }
6355
+ const filteredContent = [];
6356
+ for (let j = 0; j < content.length; j++) {
6357
+ const block = content[j];
6358
+ if (block.type === "tool_result" && "tool_use_id" in block) {
6359
+ const toolUseId = block.tool_use_id;
6360
+ if (!toolUseIds.has(toolUseId)) {
6361
+ orphanedToolResultCount++;
6362
+ if (logger) {
6363
+ logger.warn(`Removing orphaned tool_result block referencing missing tool_use_id: ${toolUseId}`);
6364
+ }
6365
+ continue;
6366
+ }
6367
+ }
6368
+ filteredContent.push(block);
6369
+ }
6370
+ if (filteredContent.length > 0) {
6371
+ result.push({ ...message, content: filteredContent });
6372
+ }
6373
+ continue;
6334
6374
  }
6375
+ result.push(message);
6335
6376
  }
6336
- if (orphanedCount > 0 && logger) {
6337
- logger.log(`Tool pairing integrity: removed ${orphanedCount} orphaned tool_result block(s) after truncation`);
6377
+ if ((orphanedToolResultCount > 0 || orphanedToolUseCount > 0) && logger) {
6378
+ const parts = [];
6379
+ if (orphanedToolResultCount > 0) {
6380
+ parts.push(`${orphanedToolResultCount} orphaned tool_result block(s)`);
6381
+ }
6382
+ if (orphanedToolUseCount > 0) {
6383
+ parts.push(`${orphanedToolUseCount} orphaned tool_use block(s)`);
6384
+ }
6385
+ logger.log(`Tool pairing integrity: removed ${parts.join(" and ")} after truncation`);
6338
6386
  }
6339
6387
  return result;
6340
6388
  };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-MNS37QTQ.js";
5
+ } from "./chunk-BU5TP3BH.js";
6
6
  import {
7
7
  GenericCreditDeductTransaction,
8
8
  ImageEditUsageTransaction,
@@ -10,7 +10,7 @@ import {
10
10
  RealtimeVoiceUsageTransaction,
11
11
  TextGenerationUsageTransaction,
12
12
  TransferCreditTransaction
13
- } from "./chunk-FQDYYJMI.js";
13
+ } from "./chunk-OHR7UCTC.js";
14
14
 
15
15
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
16
16
  import { z } from "zod";
@@ -228,6 +228,7 @@ var b4mLLMTools = z3.enum([
228
228
  // File operation tools
229
229
  "file_read",
230
230
  "create_file",
231
+ "edit_local_file",
231
232
  "glob_files",
232
233
  "grep_search",
233
234
  "delete_file",
@@ -4047,6 +4048,13 @@ var SlackEvents;
4047
4048
  SlackEvents2["SLACK_COMMAND_COMPLETED"] = "Slack Command Completed";
4048
4049
  SlackEvents2["SLACK_MCP_TOOL_INVOKED"] = "Slack MCP Tool Invoked";
4049
4050
  SlackEvents2["SLACK_BULK_OPERATION"] = "Slack Bulk Operation Executed";
4051
+ SlackEvents2["COMMAND_PROCESSED"] = "Slack Command Processed";
4052
+ SlackEvents2["COMMAND_FAILED"] = "Slack Command Failed";
4053
+ SlackEvents2["APP_CREATED"] = "Slack App Created";
4054
+ SlackEvents2["WORKSPACE_DEACTIVATED"] = "Slack Workspace Deactivated";
4055
+ SlackEvents2["CHANNEL_EXPORT_STARTED"] = "Slack Channel Export Started";
4056
+ SlackEvents2["CHANNEL_EXPORT_COMPLETED"] = "Slack Channel Export Completed";
4057
+ SlackEvents2["CHANNEL_EXPORT_FAILED"] = "Slack Channel Export Failed";
4050
4058
  })(SlackEvents || (SlackEvents = {}));
4051
4059
 
4052
4060
  // ../../b4m-core/packages/common/dist/src/schemas/team.js
@@ -5454,6 +5462,95 @@ var JiraApi = class {
5454
5462
  errors: formattedErrors
5455
5463
  };
5456
5464
  }
5465
+ /**
5466
+ * Bulk transition multiple issues to new statuses in a single API call.
5467
+ * Uses the Jira Cloud Bulk Transition API.
5468
+ * Supports up to 1000 issues per request.
5469
+ *
5470
+ * Note: This is an async operation - returns a task ID for tracking progress.
5471
+ */
5472
+ async bulkTransitionIssues(params) {
5473
+ const { issues } = params;
5474
+ console.error(`[Jira] bulkTransitionIssues called with ${issues.length} issue(s)`);
5475
+ if (issues.length === 0) {
5476
+ console.error("[Jira] bulkTransitionIssues: No issues provided, returning early");
5477
+ return { taskId: "", message: "No issues to transition", issueCount: 0 };
5478
+ }
5479
+ if (issues.length > 1e3) {
5480
+ console.error(`[Jira] bulkTransitionIssues: Exceeded 1000 issue limit (${issues.length})`);
5481
+ throw new Error("Bulk transition is limited to 1000 issues per request. Please split your request.");
5482
+ }
5483
+ const transitionGroups = {};
5484
+ for (const issue of issues) {
5485
+ if (!transitionGroups[issue.transitionId]) {
5486
+ transitionGroups[issue.transitionId] = [];
5487
+ }
5488
+ transitionGroups[issue.transitionId].push(issue.issueIdOrKey);
5489
+ }
5490
+ const bulkTransitionInputs = Object.entries(transitionGroups).map(([transitionId, selectedIssueIdsOrKeys]) => ({
5491
+ selectedIssueIdsOrKeys,
5492
+ transitionId
5493
+ }));
5494
+ console.error(`[Jira] bulkTransitionIssues: Grouped into ${bulkTransitionInputs.length} transition group(s)`);
5495
+ const result = await this.request("POST", "/bulk/issues/transition", {
5496
+ body: { bulkTransitionInputs }
5497
+ });
5498
+ console.error(`[Jira] bulkTransitionIssues: Task created with ID ${result.taskId}`);
5499
+ return {
5500
+ taskId: result.taskId,
5501
+ message: `Bulk transition started for ${issues.length} issue(s).`,
5502
+ issueCount: issues.length
5503
+ };
5504
+ }
5505
+ /**
5506
+ * Bulk update labels on multiple issues in a single API call.
5507
+ * Uses the Jira Cloud Bulk Edit API.
5508
+ * Supports up to 1000 issues per request.
5509
+ *
5510
+ * Note: This is an async operation - returns a task ID for tracking progress.
5511
+ *
5512
+ * Why only labels? Jira's Bulk Edit API has significant limitations:
5513
+ * - Summary, description, assignee fields are NOT supported for bulk editing
5514
+ * - Priority and issueType require IDs and have inconsistent behavior
5515
+ * - Labels is the most reliable and commonly used bulk operation
5516
+ * See: https://community.atlassian.com/forums/Jira-questions/Bulk-Change-Description-Field/qaq-p/897762
5517
+ */
5518
+ async bulkUpdateIssues(params) {
5519
+ const { issueIdsOrKeys, labels } = params;
5520
+ console.error(`[Jira] bulkUpdateIssues called with ${issueIdsOrKeys.length} issue(s), action: ${labels.action}`);
5521
+ if (issueIdsOrKeys.length === 0) {
5522
+ console.error("[Jira] bulkUpdateIssues: No issues provided, returning early");
5523
+ return { taskId: "", message: "No issues to update", issueCount: 0 };
5524
+ }
5525
+ if (issueIdsOrKeys.length > 1e3) {
5526
+ console.error(`[Jira] bulkUpdateIssues: Exceeded 1000 issue limit (${issueIdsOrKeys.length})`);
5527
+ throw new Error("Bulk update is limited to 1000 issues per request. Please split your request.");
5528
+ }
5529
+ const selectedActions = ["labels"];
5530
+ const editedFieldsInput = {
5531
+ labelsFields: [
5532
+ {
5533
+ fieldId: "labels",
5534
+ labels: labels.values.map((name) => ({ name })),
5535
+ bulkEditMultiSelectFieldOption: labels.action
5536
+ }
5537
+ ]
5538
+ };
5539
+ console.error(`[Jira] bulkUpdateIssues: Updating labels [${labels.values.join(", ")}] with action ${labels.action}`);
5540
+ const result = await this.request("POST", "/bulk/issues/fields", {
5541
+ body: {
5542
+ selectedActions,
5543
+ selectedIssueIdsOrKeys: issueIdsOrKeys,
5544
+ editedFieldsInput
5545
+ }
5546
+ });
5547
+ console.error(`[Jira] bulkUpdateIssues: Task created with ID ${result.taskId}`);
5548
+ return {
5549
+ taskId: result.taskId,
5550
+ message: `Bulk label update started for ${issueIdsOrKeys.length} issue(s). Action: ${labels.action}.`,
5551
+ issueCount: issueIdsOrKeys.length
5552
+ };
5553
+ }
5457
5554
  };
5458
5555
 
5459
5556
  // ../../b4m-core/packages/common/dist/src/atlassian/config.js
@@ -5531,10 +5628,10 @@ var atlassianDescriptions = {
5531
5628
  confluence_list_pages: "List all pages in a Confluence space. Use usePersonalSpace: true to automatically list pages from your personal space, provide a specific spaceId, or omit both to list pages from all accessible spaces.",
5532
5629
  confluence_delete_page: "\u26A0\uFE0F DESTRUCTIVE PREVIEW-FIRST TOOL: ALWAYS call TWICE. First call: MUST use confirmed=false (or omit) to show preview. Second call: Use confirmed=true ONLY after user explicitly confirms. PERMANENTLY deletes a Confluence page. Cannot be undone.",
5533
5630
  // Jira tools
5534
- jira_get_issue: "Retrieve a Jira issue by key (e.g., PROJ-123). Returns issue details including summary, description, status, assignee, and custom fields.",
5535
- jira_create_issue: "Create a new Jira issue. Requires project key, summary, issue type name. Optionally set description, priority, assignee, labels, and parent (for subtasks).",
5536
- jira_update_issue: "Update an existing Jira issue. Can update summary, description, priority, labels, and other fields.",
5537
- jira_search_issues: "Search for Jira issues using JQL (Jira Query Language). Returns matching issues with full details.",
5631
+ jira_get_issue: "[JIRA ONLY] Retrieve a Jira issue by key (e.g., PROJ-123, not #1). DO NOT use for GitHub issues - if user mentions owner/repo format, use GitHub tools instead. Returns issue details including summary, description, status, assignee, and custom fields.",
5632
+ jira_create_issue: "[JIRA ONLY] Create a new Jira issue. DO NOT use for GitHub repositories in owner/repo format. Requires project key, summary, issue type name. Optionally set description, priority, assignee, labels, and parent (for subtasks).",
5633
+ jira_update_issue: "[JIRA ONLY] Update an existing Jira issue. DO NOT use for GitHub issues or repositories in owner/repo format - use update_issue or update_project_item_fields instead. Can update summary, description, priority, labels, and other fields.",
5634
+ jira_search_issues: "[JIRA ONLY] Search for Jira issues using JQL (Jira Query Language). DO NOT use when user mentions GitHub repositories in owner/repo format. Returns matching issues with full details.",
5538
5635
  jira_list_projects: "List all accessible Jira projects. Returns project keys, names, and details. Use this to discover project keys when creating or updating issues.",
5539
5636
  jira_get_project: "Get detailed information about a specific Jira project.",
5540
5637
  jira_list_issue_types: "List available issue types for a project (e.g., Task, Epic, Subtask). Use this to discover available issue type names, especially for projects with custom issue types.",
@@ -5551,10 +5648,10 @@ var MCP_PROVIDER_METADATA = {
5551
5648
  github: {
5552
5649
  defaultToolDescriptions: {
5553
5650
  // Core GitHub tools (must match b4m-core/packages/mcp/src/github/index.ts)
5554
- create_issue: "Create a new issue in a GitHub repository. Requires repository owner, repository name, issue title, and optional body, labels, and assignees.",
5555
- update_issue: "Update an existing GitHub issue. Can modify title, body, state (open/closed), labels, assignees, and issue type (native GitHub issue types like Bug/Feature/Task). Use list_org_issue_types to see available types. Requires repository owner, repository name, and issue number.",
5556
- list_issues: 'List issues for a GitHub repository with optional filters (state, labels, assignee, type). Can filter by native issue type like "Bug" or "Feature". Returns issue details including title, body, status, and metadata.',
5557
- get_issue: "Get detailed information about a specific GitHub issue by number. Returns full issue details including body, comments count, milestone, and timestamps.",
5651
+ create_issue: "[GITHUB ONLY] Create a new issue in a GitHub repository. Use when user mentions owner/repo format. DO NOT use jira_create_issue for GitHub repos. Requires repository owner, repository name, issue title, and optional body, labels, and assignees.",
5652
+ update_issue: "[GITHUB ONLY] Update an existing GitHub issue in owner/repo format. DO NOT use jira_update_issue for GitHub - jira_update_issue is ONLY for Jira issues with keys like PROJ-123. Can modify title, body, state (open/closed), labels, assignees, and issue type. Use list_org_issue_types to see available types. Requires repository owner, repository name, and issue number. IMPORTANT: DO NOT use this tool to update GitHub Projects v2 fields like Priority, Size, Iteration, Estimate, Start Date, Target Date, or Status - those are PROJECT FIELDS and require update_project_item_fields instead. This tool is ONLY for standard issue properties (title, body, state, labels, assignees).",
5653
+ list_issues: "[GITHUB ONLY] List issues for a GitHub repository in owner/repo format. DO NOT use jira_search_issues for GitHub. Can filter by state, labels, assignee, type. Returns issue details including title, body, status, and metadata.",
5654
+ get_issue: "[GITHUB ONLY] Get detailed information about a specific GitHub issue by number. Use when user mentions owner/repo and issue #1. DO NOT use jira_get_issue. Returns full issue details including body, comments count, milestone, timestamps, node_id (for Projects v2), and associated GitHub Projects.",
5558
5655
  search_code: "Search for code across GitHub repositories using GitHub code search syntax. Returns matching code snippets with file paths, line numbers, and repository information.",
5559
5656
  // Repository discovery and management
5560
5657
  list_repositories: "List all GitHub repositories accessible to the authenticated user. Supports filtering by visibility (public/private) and affiliation (owner/collaborator/organization_member). Returns repository metadata including name, description, language, stars, and activity.",
@@ -5568,6 +5665,12 @@ var MCP_PROVIDER_METADATA = {
5568
5665
  list_commits: "List commit history for a GitHub repository with optional filters (branch, file path, author). Returns commit SHA, message, author, date, and statistics.",
5569
5666
  get_commit: "Get detailed information about a specific commit including full message, author, committer, file changes, and diff statistics.",
5570
5667
  list_org_issue_types: "List available native GitHub issue types for an organization (Bug, Feature, Task, etc.). Use this to discover what issue types can be set on issues in the organization.",
5668
+ // GitHub Projects v2 tools
5669
+ list_org_projects: "List all GitHub Projects (v2) for an organization. Returns project IDs, titles, descriptions, and URLs. Use this to discover available projects before managing project fields.",
5670
+ list_project_fields: "List all fields for a GitHub Project (Status, Priority, Size, Iteration, etc.). Returns field IDs, data types, and available options (for single-select fields). Required to get field IDs and option IDs before updating project item fields.",
5671
+ get_project_item: "Get a GitHub issue as a project item. CRITICAL: This returns the item_id (starts with PVTI_) that you MUST use for update_project_item_fields - DO NOT use the issue node_id (starts with I_) from get_issue. WORKFLOW: Always call this BEFORE update_project_item_fields to get the correct item_id. If this tool returns an error (issue not in project), you must call add_issue_to_project first. Returns current field values and the item_id (PVTI_) needed for updates.",
5672
+ add_issue_to_project: '\u26A0\uFE0F PREVIEW-FIRST TOOL: Add a GitHub issue to a project. CRITICAL: Call this when get_project_item fails (issue not in project yet). After adding, call get_project_item to get the item_id (PVTI_) before updating fields. Use get_issue to get the issue node_id first. IMPORTANT: Always include display parameters for human-readable preview: display_project_name (from list_org_projects), display_issue_title (from get_issue like "#2 - Login issue"), and display_repository (from get_issue like "owner/repo"). Returns the new project item ID.',
5673
+ update_project_item_fields: '\u26A0\uFE0F PREVIEW-FIRST TOOL: ALWAYS call TWICE. Update one or more fields on a GitHub Project item (Priority, Size, Iteration, Estimate, Start Date, Target Date, Status). USE THIS TOOL when user asks to update Priority, Size, Iteration, Estimate, Start Date, Target Date, or Status on an issue that belongs to a GitHub Project - these are PROJECT FIELDS, not issue labels or properties. Supports both single field updates and batch updates. WORKFLOW: (1) Call get_project_item to get the item_id (starts with PVTI_) - if this fails, the issue is not in the project yet, so call add_issue_to_project first. (2) Call list_project_fields to get field IDs. (3) Call update_project_item_fields with the PVTI_ item_id. CRITICAL: The item_id parameter MUST be a ProjectV2Item ID (starts with PVTI_) from get_project_item, NOT the issue node_id (starts with I_) from get_issue. Using the wrong ID will cause all updates to fail. For each field in updates array, provide: field_id, value (actual ID/number/date), field_name (human name), new_value (human-readable for preview). Example: {item_id: "PVTI_lADO...", updates: [{field_id: "PVTF_...", value: "option_id", field_name: "Priority", new_value: "P1"}]}',
5571
5674
  // Legacy tool names (for backwards compatibility)
5572
5675
  github_list_repositories: "List GitHub repositories accessible to the connected account.",
5573
5676
  github_get_repository: "Fetch detailed information about a specific GitHub repository.",
File without changes
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-MNS37QTQ.js";
10
+ } from "./chunk-BU5TP3BH.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-FQDYYJMI.js";
14
+ } from "./chunk-OHR7UCTC.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-MNS37QTQ.js";
9
+ } from "./chunk-BU5TP3BH.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-FQDYYJMI.js";
14
+ } from "./chunk-OHR7UCTC.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-FJM3L5N3.js";
6
- import "./chunk-MNS37QTQ.js";
5
+ } from "./chunk-RJFNIMVH.js";
6
+ import "./chunk-BU5TP3BH.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
- import "./chunk-FQDYYJMI.js";
8
+ import "./chunk-OHR7UCTC.js";
9
9
  import "./chunk-PDX44BCA.js";
10
10
  export {
11
11
  createFabFile,
File without changes
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  getEffectiveApiKey,
5
5
  getOpenWeatherKey,
6
6
  getSerperKey
7
- } from "./chunk-NBCK5RYI.js";
8
- import "./chunk-LZXUR7SE.js";
9
- import "./chunk-FJM3L5N3.js";
7
+ } from "./chunk-ZHCX7BLB.js";
8
+ import "./chunk-ID4NS6KF.js";
9
+ import "./chunk-RJFNIMVH.js";
10
10
  import {
11
11
  BFLImageService,
12
12
  BaseStorage,
@@ -15,7 +15,7 @@ import {
15
15
  OpenAIBackend,
16
16
  OpenAIImageService,
17
17
  XAIImageService
18
- } from "./chunk-MNS37QTQ.js";
18
+ } from "./chunk-BU5TP3BH.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -73,7 +73,7 @@ import {
73
73
  XAI_IMAGE_MODELS,
74
74
  b4mLLMTools,
75
75
  getMcpProviderMetadata
76
- } from "./chunk-FQDYYJMI.js";
76
+ } from "./chunk-OHR7UCTC.js";
77
77
  import {
78
78
  __require
79
79
  } from "./chunk-PDX44BCA.js";
@@ -988,8 +988,8 @@ import { Box as Box6 } from "ink";
988
988
  import React6 from "react";
989
989
  import { Box as Box5, Text as Text6 } from "ink";
990
990
  import Spinner from "ink-spinner";
991
- var ThoughtStream = React6.memo(function ThoughtStream2({ steps }) {
992
- return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React6.createElement(Box5, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.type === "action" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
991
+ var ThoughtStream = React6.memo(function ThoughtStream2({ isThinking }) {
992
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, isThinking && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Thinking...")));
993
993
  });
994
994
 
995
995
  // src/store/index.ts
@@ -1034,12 +1034,6 @@ var useCliStore = create((set) => ({
1034
1034
  // UI state
1035
1035
  isThinking: false,
1036
1036
  setIsThinking: (thinking) => set({ isThinking: thinking }),
1037
- agentSteps: [],
1038
- addAgentStep: (step) => set((state) => ({
1039
- agentSteps: [...state.agentSteps, step]
1040
- })),
1041
- setAgentSteps: (steps) => set({ agentSteps: steps }),
1042
- clearAgentSteps: () => set({ agentSteps: [] }),
1043
1037
  // Permission prompt
1044
1038
  permissionPrompt: null,
1045
1039
  setPermissionPrompt: (prompt) => set({ permissionPrompt: prompt }),
@@ -1054,11 +1048,10 @@ var useCliStore = create((set) => ({
1054
1048
  // src/components/AgentThinking.tsx
1055
1049
  var AgentThinking = React7.memo(function AgentThinking2() {
1056
1050
  const isThinking = useCliStore((state) => state.isThinking);
1057
- const agentSteps = useCliStore((state) => state.agentSteps);
1058
1051
  if (!isThinking) {
1059
1052
  return null;
1060
1053
  }
1061
- return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
1054
+ return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { isThinking }));
1062
1055
  });
1063
1056
 
1064
1057
  // src/components/PermissionPrompt.tsx
@@ -1096,7 +1089,10 @@ function PermissionPrompt({
1096
1089
  { label: "\u2713 Allow once", value: "allow-once" },
1097
1090
  { label: "\u2717 Deny", value: "deny" }
1098
1091
  ];
1099
- const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
1092
+ const MAX_ARGS_LENGTH = 500;
1093
+ const rawArgsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
1094
+ const argsString = rawArgsString.length > MAX_ARGS_LENGTH ? rawArgsString.slice(0, MAX_ARGS_LENGTH) + `
1095
+ ... (${rawArgsString.length - MAX_ARGS_LENGTH} more chars)` : rawArgsString;
1100
1096
  return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Tool: "), /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Action: "), /* @__PURE__ */ React8.createElement(Text7, null, toolDescription)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Arguments:"), /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Preview:"), /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
1101
1097
  }
1102
1098
 
@@ -2381,15 +2377,19 @@ var ConfigStore = class {
2381
2377
  throw error;
2382
2378
  }
2383
2379
  }
2384
- this.projectConfigDir = findProjectConfigDir();
2385
2380
  let projectConfig = null;
2386
2381
  let projectLocalConfig = null;
2387
- if (this.projectConfigDir) {
2388
- projectConfig = await loadProjectConfig(this.projectConfigDir);
2389
- projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
2390
- if (projectConfig) {
2391
- console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
2382
+ if (process.env.B4M_NO_PROJECT_CONFIG !== "1") {
2383
+ this.projectConfigDir = findProjectConfigDir();
2384
+ if (this.projectConfigDir) {
2385
+ projectConfig = await loadProjectConfig(this.projectConfigDir);
2386
+ projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
2387
+ if (projectConfig) {
2388
+ console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
2389
+ }
2392
2390
  }
2391
+ } else {
2392
+ this.projectConfigDir = null;
2393
2393
  }
2394
2394
  this.config = mergeConfigs(globalConfig, projectConfig, projectLocalConfig);
2395
2395
  return this.config;
@@ -5489,8 +5489,8 @@ async function processAndStoreImages(images, context) {
5489
5489
  const buffer = await downloadImage(image);
5490
5490
  const fileType = await fileTypeFromBuffer2(buffer);
5491
5491
  const filename = `${uuidv46()}.${fileType?.ext}`;
5492
- const path16 = await context.imageGenerateStorage.upload(buffer, filename, {});
5493
- return path16;
5492
+ const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
5493
+ return path17;
5494
5494
  }));
5495
5495
  }
5496
5496
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -6702,8 +6702,8 @@ async function processAndStoreImage(imageUrl, context) {
6702
6702
  const buffer = await downloadImage2(imageUrl);
6703
6703
  const fileType = await fileTypeFromBuffer3(buffer);
6704
6704
  const filename = `${uuidv47()}.${fileType?.ext}`;
6705
- const path16 = await context.imageGenerateStorage.upload(buffer, filename, {});
6706
- return path16;
6705
+ const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
6706
+ return path17;
6707
6707
  }
6708
6708
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
6709
6709
  await context.onFinish?.("edit_image", storedImagePath);
@@ -9491,6 +9491,104 @@ BLOCKED OPERATIONS:
9491
9491
  })
9492
9492
  };
9493
9493
 
9494
+ // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
9495
+ import { promises as fs11 } from "fs";
9496
+ import { existsSync as existsSync7 } from "fs";
9497
+ import path13 from "path";
9498
+ import { diffLines as diffLines3 } from "diff";
9499
+ function generateDiff(original, modified) {
9500
+ const differences = diffLines3(original, modified);
9501
+ let diffString = "";
9502
+ let additions = 0;
9503
+ let deletions = 0;
9504
+ differences.forEach((part) => {
9505
+ if (part.added) {
9506
+ additions += part.count || 0;
9507
+ diffString += part.value.split("\n").filter((line) => line).map((line) => `+ ${line}`).join("\n");
9508
+ if (diffString && !diffString.endsWith("\n"))
9509
+ diffString += "\n";
9510
+ } else if (part.removed) {
9511
+ deletions += part.count || 0;
9512
+ diffString += part.value.split("\n").filter((line) => line).map((line) => `- ${line}`).join("\n");
9513
+ if (diffString && !diffString.endsWith("\n"))
9514
+ diffString += "\n";
9515
+ }
9516
+ });
9517
+ return { additions, deletions, diff: diffString.trim() };
9518
+ }
9519
+ async function editLocalFile(params) {
9520
+ const { path: filePath, old_string, new_string } = params;
9521
+ const normalizedPath = path13.normalize(filePath);
9522
+ const resolvedPath = path13.resolve(process.cwd(), normalizedPath);
9523
+ const cwd = path13.resolve(process.cwd());
9524
+ if (!resolvedPath.startsWith(cwd)) {
9525
+ throw new Error(`Access denied: Cannot edit files outside of current working directory`);
9526
+ }
9527
+ if (!existsSync7(resolvedPath)) {
9528
+ throw new Error(`File not found: ${filePath}`);
9529
+ }
9530
+ const currentContent = await fs11.readFile(resolvedPath, "utf-8");
9531
+ if (!currentContent.includes(old_string)) {
9532
+ const preview = old_string.length > 100 ? old_string.substring(0, 100) + "..." : old_string;
9533
+ throw new Error(`String to replace not found in file. Make sure the old_string matches exactly (including whitespace and line endings). Searched for: "${preview}"`);
9534
+ }
9535
+ const occurrences = currentContent.split(old_string).length - 1;
9536
+ if (occurrences > 1) {
9537
+ throw new Error(`Found ${occurrences} occurrences of the string to replace. Please provide a more specific old_string that matches exactly one location.`);
9538
+ }
9539
+ const newContent = currentContent.replace(old_string, new_string);
9540
+ await fs11.writeFile(resolvedPath, newContent, "utf-8");
9541
+ const diffResult = generateDiff(old_string, new_string);
9542
+ return `File edited successfully: ${filePath}
9543
+ Changes: +${diffResult.additions} lines, -${diffResult.deletions} lines
9544
+
9545
+ Diff:
9546
+ ${diffResult.diff}`;
9547
+ }
9548
+ var editLocalFileTool = {
9549
+ name: "edit_local_file",
9550
+ implementation: (context) => ({
9551
+ toolFn: async (value) => {
9552
+ const params = value;
9553
+ context.logger.info(`\u{1F4DD} EditLocalFile: Editing file`, {
9554
+ path: params.path,
9555
+ oldStringLength: params.old_string.length,
9556
+ newStringLength: params.new_string.length
9557
+ });
9558
+ try {
9559
+ const result = await editLocalFile(params);
9560
+ context.logger.info("\u2705 EditLocalFile: Success", { path: params.path });
9561
+ return result;
9562
+ } catch (error) {
9563
+ context.logger.error("\u274C EditLocalFile: Failed", error);
9564
+ throw error;
9565
+ }
9566
+ },
9567
+ toolSchema: {
9568
+ name: "edit_local_file",
9569
+ description: "Edit a file by replacing a specific string with new content. The old_string must match exactly one location in the file (including whitespace). Use this for precise edits to existing files. For creating new files or complete rewrites, use create_file instead.",
9570
+ parameters: {
9571
+ type: "object",
9572
+ properties: {
9573
+ path: {
9574
+ type: "string",
9575
+ description: "Path to the file to edit (relative to current working directory)"
9576
+ },
9577
+ old_string: {
9578
+ type: "string",
9579
+ description: "The exact string to find and replace. Must match exactly one location in the file, including all whitespace and line endings."
9580
+ },
9581
+ new_string: {
9582
+ type: "string",
9583
+ description: "The string to replace old_string with. Can be empty to delete the old_string."
9584
+ }
9585
+ },
9586
+ required: ["path", "old_string", "new_string"]
9587
+ }
9588
+ }
9589
+ })
9590
+ };
9591
+
9494
9592
  // ../../b4m-core/packages/services/dist/src/llm/tools/index.js
9495
9593
  var tools = {
9496
9594
  dice_roll: diceRollTool,
@@ -9516,6 +9614,7 @@ var tools = {
9516
9614
  planet_visibility: planetVisibilityTool,
9517
9615
  file_read: fileReadTool,
9518
9616
  create_file: createFileTool,
9617
+ edit_local_file: editLocalFileTool,
9519
9618
  glob_files: globFilesTool,
9520
9619
  grep_search: grepSearchTool,
9521
9620
  delete_file: deleteFileTool,
@@ -9759,10 +9858,10 @@ var ToolErrorType;
9759
9858
  // src/utils/diffPreview.ts
9760
9859
  import * as Diff from "diff";
9761
9860
  import { readFile } from "fs/promises";
9762
- import { existsSync as existsSync7 } from "fs";
9861
+ import { existsSync as existsSync8 } from "fs";
9763
9862
  async function generateFileDiffPreview(args) {
9764
9863
  try {
9765
- if (!existsSync7(args.path)) {
9864
+ if (!existsSync8(args.path)) {
9766
9865
  const lines2 = args.content.split("\n");
9767
9866
  const preview = lines2.slice(0, 20).join("\n");
9768
9867
  const hasMore = lines2.length > 20;
@@ -9784,18 +9883,26 @@ ${preview}${hasMore ? `
9784
9883
  // Show 3 lines of context around changes
9785
9884
  );
9786
9885
  const lines = patch.split("\n");
9787
- const diffLines3 = lines.slice(4);
9788
- return diffLines3.join("\n");
9886
+ const diffLines4 = lines.slice(4);
9887
+ return diffLines4.join("\n");
9789
9888
  } catch (error) {
9790
9889
  return `[Error generating diff preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
9791
9890
  }
9792
9891
  }
9892
+ function generateEditLocalFilePreview(args) {
9893
+ const patch = Diff.createPatch(args.path, args.old_string, args.new_string, "Current", "Proposed", { context: 3 });
9894
+ const lines = patch.split("\n");
9895
+ const diffLines4 = lines.slice(4);
9896
+ return `[Edit in: ${args.path}]
9897
+
9898
+ ${diffLines4.join("\n")}`;
9899
+ }
9793
9900
  async function generateFileDeletePreview(args) {
9794
9901
  try {
9795
- if (!existsSync7(args.path)) {
9902
+ if (!existsSync8(args.path)) {
9796
9903
  return `[File does not exist: ${args.path}]`;
9797
9904
  }
9798
- const stats = await import("fs/promises").then((fs13) => fs13.stat(args.path));
9905
+ const stats = await import("fs/promises").then((fs14) => fs14.stat(args.path));
9799
9906
  return `[File will be deleted]
9800
9907
 
9801
9908
  Path: ${args.path}
@@ -9807,8 +9914,8 @@ Last modified: ${stats.mtime.toLocaleString()}`;
9807
9914
  }
9808
9915
 
9809
9916
  // src/utils/Logger.ts
9810
- import fs11 from "fs/promises";
9811
- import path13 from "path";
9917
+ import fs12 from "fs/promises";
9918
+ import path14 from "path";
9812
9919
  import os2 from "os";
9813
9920
  var Logger2 = class _Logger {
9814
9921
  constructor() {
@@ -9831,9 +9938,9 @@ var Logger2 = class _Logger {
9831
9938
  */
9832
9939
  async initialize(sessionId) {
9833
9940
  this.sessionId = sessionId;
9834
- const debugDir = path13.join(os2.homedir(), ".bike4mind", "debug");
9835
- await fs11.mkdir(debugDir, { recursive: true });
9836
- this.logFilePath = path13.join(debugDir, `${sessionId}.txt`);
9941
+ const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
9942
+ await fs12.mkdir(debugDir, { recursive: true });
9943
+ this.logFilePath = path14.join(debugDir, `${sessionId}.txt`);
9837
9944
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
9838
9945
  }
9839
9946
  /**
@@ -9897,7 +10004,7 @@ var Logger2 = class _Logger {
9897
10004
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
9898
10005
  const logEntry = `[${timestamp}] [${level}] ${message}
9899
10006
  `;
9900
- await fs11.appendFile(this.logFilePath, logEntry, "utf-8");
10007
+ await fs12.appendFile(this.logFilePath, logEntry, "utf-8");
9901
10008
  } catch (error) {
9902
10009
  console.error("File logging failed:", error);
9903
10010
  }
@@ -10043,15 +10150,15 @@ var Logger2 = class _Logger {
10043
10150
  async cleanupOldLogs() {
10044
10151
  if (!this.fileLoggingEnabled) return;
10045
10152
  try {
10046
- const debugDir = path13.join(os2.homedir(), ".bike4mind", "debug");
10047
- const files = await fs11.readdir(debugDir);
10153
+ const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
10154
+ const files = await fs12.readdir(debugDir);
10048
10155
  const now = Date.now();
10049
10156
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
10050
10157
  for (const file of files) {
10051
- const filePath = path13.join(debugDir, file);
10052
- const stats = await fs11.stat(filePath);
10158
+ const filePath = path14.join(debugDir, file);
10159
+ const stats = await fs12.stat(filePath);
10053
10160
  if (stats.mtime.getTime() < thirtyDaysAgo) {
10054
- await fs11.unlink(filePath);
10161
+ await fs12.unlink(filePath);
10055
10162
  }
10056
10163
  }
10057
10164
  } catch (error) {
@@ -10108,10 +10215,10 @@ var SERVER_TOOLS = ["weather_info", "web_search"];
10108
10215
  var LOCAL_TOOLS = [
10109
10216
  "file_read",
10110
10217
  "create_file",
10218
+ "edit_local_file",
10111
10219
  "glob_files",
10112
10220
  "grep_search",
10113
10221
  "delete_file",
10114
- "edit_file",
10115
10222
  "dice_roll",
10116
10223
  "math_evaluate",
10117
10224
  "current_datetime",
@@ -10145,21 +10252,21 @@ var NoOpStorage = class extends BaseStorage {
10145
10252
  async upload(input, destination, options) {
10146
10253
  return `/tmp/${destination}`;
10147
10254
  }
10148
- async download(path16) {
10255
+ async download(path17) {
10149
10256
  throw new Error("Download not supported in CLI");
10150
10257
  }
10151
- async delete(path16) {
10258
+ async delete(path17) {
10152
10259
  }
10153
- async getSignedUrl(path16) {
10154
- return `/tmp/${path16}`;
10260
+ async getSignedUrl(path17) {
10261
+ return `/tmp/${path17}`;
10155
10262
  }
10156
- getPublicUrl(path16) {
10157
- return `/tmp/${path16}`;
10263
+ getPublicUrl(path17) {
10264
+ return `/tmp/${path17}`;
10158
10265
  }
10159
- async getPreview(path16) {
10160
- return `/tmp/${path16}`;
10266
+ async getPreview(path17) {
10267
+ return `/tmp/${path17}`;
10161
10268
  }
10162
- async getMetadata(path16) {
10269
+ async getMetadata(path17) {
10163
10270
  return { size: 0, contentType: "application/octet-stream" };
10164
10271
  }
10165
10272
  };
@@ -10191,11 +10298,12 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
10191
10298
  return result2;
10192
10299
  }
10193
10300
  let preview;
10194
- if (toolName === "edit_file" && args?.path && args?.content) {
10301
+ if (toolName === "edit_local_file" && args?.path && args?.old_string && typeof args?.new_string === "string") {
10195
10302
  try {
10196
- preview = await generateFileDiffPreview({
10303
+ preview = generateEditLocalFilePreview({
10197
10304
  path: args.path,
10198
- content: args.content
10305
+ old_string: args.old_string,
10306
+ new_string: args.new_string
10199
10307
  });
10200
10308
  } catch (error) {
10201
10309
  preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
@@ -10312,6 +10420,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
10312
10420
  // File operation tools (CLI-specific, local execution)
10313
10421
  file_read: {},
10314
10422
  create_file: {},
10423
+ edit_local_file: {},
10315
10424
  glob_files: {},
10316
10425
  grep_search: {},
10317
10426
  delete_file: {},
@@ -10394,6 +10503,7 @@ var DEFAULT_TOOL_CATEGORIES = {
10394
10503
  // These tools can modify files, execute code, or have other dangerous side effects
10395
10504
  // They ALWAYS require permission and cannot be trusted automatically
10396
10505
  edit_file: "prompt_always",
10506
+ edit_local_file: "prompt_always",
10397
10507
  create_file: "prompt_always",
10398
10508
  delete_file: "prompt_always",
10399
10509
  shell_execute: "prompt_always",
@@ -10560,8 +10670,8 @@ function getEnvironmentName(configApiConfig) {
10560
10670
  }
10561
10671
 
10562
10672
  // src/utils/contextLoader.ts
10563
- import * as fs12 from "fs";
10564
- import * as path14 from "path";
10673
+ import * as fs13 from "fs";
10674
+ import * as path15 from "path";
10565
10675
  import { homedir as homedir4 } from "os";
10566
10676
  var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
10567
10677
  var PROJECT_CONTEXT_FILES = [
@@ -10582,9 +10692,9 @@ function formatFileSize2(bytes) {
10582
10692
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
10583
10693
  }
10584
10694
  function tryReadContextFile(dir, filename, source) {
10585
- const filePath = path14.join(dir, filename);
10695
+ const filePath = path15.join(dir, filename);
10586
10696
  try {
10587
- const stats = fs12.lstatSync(filePath);
10697
+ const stats = fs13.lstatSync(filePath);
10588
10698
  if (stats.isDirectory()) {
10589
10699
  return null;
10590
10700
  }
@@ -10598,7 +10708,7 @@ function tryReadContextFile(dir, filename, source) {
10598
10708
  error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
10599
10709
  };
10600
10710
  }
10601
- const content = fs12.readFileSync(filePath, "utf-8");
10711
+ const content = fs13.readFileSync(filePath, "utf-8");
10602
10712
  return {
10603
10713
  filename,
10604
10714
  content,
@@ -10650,7 +10760,7 @@ ${project.content}`;
10650
10760
  }
10651
10761
  async function loadContextFiles(projectDir) {
10652
10762
  const errors = [];
10653
- const globalDir = path14.join(homedir4(), ".bike4mind");
10763
+ const globalDir = path15.join(homedir4(), ".bike4mind");
10654
10764
  const projectDirectory = projectDir || process.cwd();
10655
10765
  const [globalResult, projectResult] = await Promise.all([
10656
10766
  Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
@@ -10686,8 +10796,8 @@ function substituteArguments(template, args) {
10686
10796
  // ../../b4m-core/packages/mcp/dist/src/client.js
10687
10797
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
10688
10798
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
10689
- import path15 from "path";
10690
- import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
10799
+ import path16 from "path";
10800
+ import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
10691
10801
  var MCPClient = class {
10692
10802
  // Note: This class handles MCP server communication with repository filtering
10693
10803
  mcp;
@@ -10727,18 +10837,18 @@ var MCPClient = class {
10727
10837
  const root = process.env.INIT_CWD || process.cwd();
10728
10838
  const candidatePaths = [
10729
10839
  // When running from SST Lambda with node_modules structure (copyFiles)
10730
- path15.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
10840
+ path16.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
10731
10841
  // When running from SST Lambda deployed environment (/var/task)
10732
- path15.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10842
+ path16.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10733
10843
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
10734
- path15.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10844
+ path16.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10735
10845
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
10736
- path15.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10846
+ path16.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10737
10847
  // Original paths (backward compatibility)
10738
- path15.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10739
- path15.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
10848
+ path16.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10849
+ path16.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
10740
10850
  ];
10741
- const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
10851
+ const serverScriptPath = candidatePaths.find((p) => existsSync9(p));
10742
10852
  if (!serverScriptPath) {
10743
10853
  const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
10744
10854
  console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
@@ -11548,7 +11658,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
11548
11658
  // package.json
11549
11659
  var package_default = {
11550
11660
  name: "@bike4mind/cli",
11551
- version: "0.2.11-ja-fix-confluence-table-data-5752.17346+899c98af0",
11661
+ version: "0.2.11",
11552
11662
  type: "module",
11553
11663
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
11554
11664
  license: "UNLICENSED",
@@ -11651,11 +11761,11 @@ var package_default = {
11651
11761
  zustand: "^4.5.4"
11652
11762
  },
11653
11763
  devDependencies: {
11654
- "@bike4mind/agents": "0.1.0",
11655
- "@bike4mind/common": "2.40.1-ja-fix-confluence-table-data-5752.17346+899c98af0",
11656
- "@bike4mind/mcp": "1.20.5-ja-fix-confluence-table-data-5752.17346+899c98af0",
11657
- "@bike4mind/services": "2.35.1-ja-fix-confluence-table-data-5752.17346+899c98af0",
11658
- "@bike4mind/utils": "2.1.5-ja-fix-confluence-table-data-5752.17346+899c98af0",
11764
+ "@bike4mind/agents": "workspace:*",
11765
+ "@bike4mind/common": "workspace:*",
11766
+ "@bike4mind/mcp": "workspace:*",
11767
+ "@bike4mind/services": "workspace:*",
11768
+ "@bike4mind/utils": "workspace:*",
11659
11769
  "@types/better-sqlite3": "^7.6.13",
11660
11770
  "@types/diff": "^5.0.9",
11661
11771
  "@types/jsonwebtoken": "^9.0.4",
@@ -11667,8 +11777,7 @@ var package_default = {
11667
11777
  tsx: "^4.21.0",
11668
11778
  typescript: "^5.9.3",
11669
11779
  vitest: "^3.2.4"
11670
- },
11671
- gitHead: "899c98af0bfb597fe554bd11a5b8555eeae79f70"
11780
+ }
11672
11781
  };
11673
11782
 
11674
11783
  // src/config/constants.ts
@@ -11910,6 +12019,7 @@ Focus on:
11910
12019
  - Creating logical sequence of steps
11911
12020
  - Estimating scope and priorities
11912
12021
 
12022
+ You have read-only access to analyze code.
11913
12023
  You can explore the codebase to understand the current architecture before planning.
11914
12024
 
11915
12025
  Provide a structured plan that the main agent can execute.`,
@@ -12376,20 +12486,38 @@ Remember: Use context from previous messages to understand follow-up questions.$
12376
12486
  const lastIdx = pendingMessages.length - 1;
12377
12487
  if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
12378
12488
  const existingSteps = pendingMessages[lastIdx].metadata?.steps || [];
12489
+ const MAX_INPUT_LENGTH = 500;
12490
+ let truncatedStep = step;
12491
+ if (step.type === "action" && step.metadata?.toolInput) {
12492
+ const inputStr = typeof step.metadata.toolInput === "string" ? step.metadata.toolInput : JSON.stringify(step.metadata.toolInput);
12493
+ if (inputStr.length > MAX_INPUT_LENGTH) {
12494
+ const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
12495
+ truncatedStep = {
12496
+ ...step,
12497
+ metadata: {
12498
+ ...step.metadata,
12499
+ toolInput: truncatedInput
12500
+ }
12501
+ };
12502
+ }
12503
+ }
12379
12504
  updatePendingMessage(lastIdx, {
12380
12505
  ...pendingMessages[lastIdx],
12381
12506
  metadata: {
12382
12507
  ...pendingMessages[lastIdx].metadata,
12383
- steps: [...existingSteps, step]
12508
+ steps: [...existingSteps, truncatedStep]
12384
12509
  }
12385
12510
  });
12386
12511
  }
12387
12512
  };
12513
+ agent.on("thought", stepHandler);
12388
12514
  agent.on("action", stepHandler);
12389
12515
  orchestrator.setBeforeRunCallback((subagent, _subagentType) => {
12516
+ subagent.on("thought", stepHandler);
12390
12517
  subagent.on("action", stepHandler);
12391
12518
  });
12392
12519
  orchestrator.setAfterRunCallback((subagent, _subagentType) => {
12520
+ subagent.off("thought", stepHandler);
12393
12521
  subagent.off("action", stepHandler);
12394
12522
  });
12395
12523
  setState((prev) => ({
@@ -12458,6 +12586,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
12458
12586
  }
12459
12587
  }
12460
12588
  };
12589
+ state.agent.on("thought", stepHandler);
12461
12590
  state.agent.on("action", stepHandler);
12462
12591
  try {
12463
12592
  let messageContent = fullTemplate;
@@ -12579,6 +12708,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
12579
12708
  setState((prev) => ({ ...prev, session: sessionWithError }));
12580
12709
  setStoreSession(sessionWithError);
12581
12710
  } finally {
12711
+ state.agent.off("thought", stepHandler);
12582
12712
  state.agent.off("action", stepHandler);
12583
12713
  }
12584
12714
  };
@@ -12900,7 +13030,6 @@ Custom Commands:
12900
13030
  logger.debug("=== Session Resumed ===");
12901
13031
  setState((prev) => ({ ...prev, session: loadedSession }));
12902
13032
  setStoreSession(loadedSession);
12903
- useCliStore.getState().clearAgentSteps();
12904
13033
  useCliStore.getState().clearPendingMessages();
12905
13034
  usageCache = null;
12906
13035
  console.log(`
@@ -13136,7 +13265,6 @@ Custom Commands:
13136
13265
  logger.debug("=== New Session Started via /clear ===");
13137
13266
  setState((prev) => ({ ...prev, session: newSession }));
13138
13267
  setStoreSession(newSession);
13139
- useCliStore.getState().clearAgentSteps();
13140
13268
  useCliStore.getState().clearPendingMessages();
13141
13269
  usageCache = null;
13142
13270
  console.log("New session started.");
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-FQDYYJMI.js";
4
+ } from "./chunk-OHR7UCTC.js";
5
5
  import "./chunk-PDX44BCA.js";
6
6
 
7
7
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/llmMarkdownGenerator.js
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-FQDYYJMI.js";
4
+ } from "./chunk-OHR7UCTC.js";
5
5
  import "./chunk-PDX44BCA.js";
6
6
 
7
7
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/markdownGenerator.js
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-NBCK5RYI.js";
6
- import "./chunk-MNS37QTQ.js";
5
+ } from "./chunk-ZHCX7BLB.js";
6
+ import "./chunk-BU5TP3BH.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
- import "./chunk-FQDYYJMI.js";
8
+ import "./chunk-OHR7UCTC.js";
9
9
  import "./chunk-PDX44BCA.js";
10
10
  export {
11
11
  findMostSimilarMemento,
File without changes
@@ -295,7 +295,7 @@ import {
295
295
  validateReactArtifactV2,
296
296
  validateSvgArtifactV2,
297
297
  wikiMarkupToAdf
298
- } from "./chunk-FQDYYJMI.js";
298
+ } from "./chunk-OHR7UCTC.js";
299
299
  import "./chunk-PDX44BCA.js";
300
300
  export {
301
301
  ALL_IMAGE_MODELS,
@@ -120,7 +120,7 @@ import {
120
120
  validateMermaidSyntax,
121
121
  warmUpSettingsCache,
122
122
  withRetry
123
- } from "./chunk-MNS37QTQ.js";
123
+ } from "./chunk-BU5TP3BH.js";
124
124
  import {
125
125
  Logger,
126
126
  NotificationDeduplicator,
@@ -129,7 +129,7 @@ import {
129
129
  postLowCreditsNotificationToSlack,
130
130
  postMessageToSlack
131
131
  } from "./chunk-AMDXHL6S.js";
132
- import "./chunk-FQDYYJMI.js";
132
+ import "./chunk-OHR7UCTC.js";
133
133
  import "./chunk-PDX44BCA.js";
134
134
  export {
135
135
  AWSBackend,
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-LZXUR7SE.js";
6
- import "./chunk-MNS37QTQ.js";
5
+ } from "./chunk-ID4NS6KF.js";
6
+ import "./chunk-BU5TP3BH.js";
7
7
  import "./chunk-AMDXHL6S.js";
8
- import "./chunk-FQDYYJMI.js";
8
+ import "./chunk-OHR7UCTC.js";
9
9
  import "./chunk-PDX44BCA.js";
10
10
  export {
11
11
  SubtractCreditsSchema,
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.11-ja-fix-confluence-table-data-5752.17346+899c98af0",
3
+ "version": "0.2.11",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -30,15 +30,6 @@
30
30
  "dist",
31
31
  "bin"
32
32
  ],
33
- "scripts": {
34
- "dev": "tsx src/index.tsx",
35
- "build": "tsup",
36
- "typecheck": "tsc --noEmit",
37
- "test": "vitest run",
38
- "test:watch": "vitest",
39
- "start": "node dist/index.js",
40
- "prepublishOnly": "pnpm build"
41
- },
42
33
  "dependencies": {
43
34
  "@anthropic-ai/sdk": "^0.22.0",
44
35
  "@aws-sdk/client-apigatewaymanagementapi": "3.654.0",
@@ -103,11 +94,6 @@
103
94
  "zustand": "^4.5.4"
104
95
  },
105
96
  "devDependencies": {
106
- "@bike4mind/agents": "0.1.0",
107
- "@bike4mind/common": "2.40.1-ja-fix-confluence-table-data-5752.17346+899c98af0",
108
- "@bike4mind/mcp": "1.20.5-ja-fix-confluence-table-data-5752.17346+899c98af0",
109
- "@bike4mind/services": "2.35.1-ja-fix-confluence-table-data-5752.17346+899c98af0",
110
- "@bike4mind/utils": "2.1.5-ja-fix-confluence-table-data-5752.17346+899c98af0",
111
97
  "@types/better-sqlite3": "^7.6.13",
112
98
  "@types/diff": "^5.0.9",
113
99
  "@types/jsonwebtoken": "^9.0.4",
@@ -118,7 +104,19 @@
118
104
  "tsup": "^8.5.1",
119
105
  "tsx": "^4.21.0",
120
106
  "typescript": "^5.9.3",
121
- "vitest": "^3.2.4"
107
+ "vitest": "^3.2.4",
108
+ "@bike4mind/agents": "0.1.0",
109
+ "@bike4mind/common": "2.41.0",
110
+ "@bike4mind/mcp": "1.21.0",
111
+ "@bike4mind/services": "2.36.0",
112
+ "@bike4mind/utils": "2.1.5"
122
113
  },
123
- "gitHead": "899c98af0bfb597fe554bd11a5b8555eeae79f70"
124
- }
114
+ "scripts": {
115
+ "dev": "tsx src/index.tsx",
116
+ "build": "tsup",
117
+ "typecheck": "tsc --noEmit",
118
+ "test": "vitest run",
119
+ "test:watch": "vitest",
120
+ "start": "node dist/index.js"
121
+ }
122
+ }