@xagent/x-cli 1.1.67 → 1.1.69

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
@@ -1,4 +1,6 @@
1
- ## 1.1.67 Logo Assets & NPM Publication Complete
1
+ <!-- Test comment for PR creation -->
2
+
3
+ ## 1.1.69 – Logo Assets & NPM Publication Complete
2
4
 
3
5
  ✅ **Live on NPM**: [@xagent/x-cli](https://www.npmjs.com/package/@xagent/x-cli) - Fully published and ready for global installation
4
6
 
@@ -45,6 +47,16 @@ A conversational AI CLI tool powered by Grok with **Claude Code-level intelligen
45
47
  - **📋 User Approval Workflow**: Complete plan review and confirmation before execution
46
48
  - **⚡ Performance Optimized**: Fast exploration (1-15 seconds) with intelligent caching and filtering
47
49
 
50
+ ### 🚀 **P5: Research → Recommend → Execute → Auto-Doc Workflow** (Latest)
51
+
52
+ - **🤖 Research Phase**: Intelligent context loading from `.agent/` docs with Issues/Options analysis
53
+ - **💡 Recommend Phase**: Structured decision framework with trade-offs, effort/risk analysis, and confidence scoring
54
+ - **⚡ Execute Phase**: Sequential TODO execution with adaptive recovery, real-time diffs, and safety guarantees
55
+ - **📝 Auto-Doc Phase**: Automatic completion documentation with lesson learning and SOP candidate detection
56
+ - **🛡️ Safety First**: All changes have patches, backups, and git commits; adaptive error recovery
57
+ - **🔄 Resilient**: Handles execution failures gracefully with re-planning capabilities
58
+ - **📚 Knowledge Base**: Builds institutional memory through automatic documentation accumulation
59
+
48
60
  ### 🎨 **P4: UX Refinement - Claude Code Feel**
49
61
 
50
62
  - **🎭 Enhanced Welcome Banner**: Professional ASCII art with context-aware status display
@@ -1078,14 +1090,14 @@ To add yourself as a contributor:
1078
1090
 
1079
1091
  - **[@unblock-everything](https://github.com/unblock-everything)** — [x.ai](https://x.ai) — Cold-ass honkey 😎
1080
1092
  - **[@Bucko89](https://github.com/Bucko89)** — [GMA](https://getmyagencies.com) — Grinding daily
1081
- - **[@base-buzz](https://github.com/base-buzz)** — [Meta](team.meta.com)
1093
+ - **[@base-buzz](https://github.com/base-buzz)** — [BaseBUzz](team.basebuzz.com)
1082
1094
 
1083
1095
  _Want to see your name here? Check out our [Contributing Guide](CONTRIBUTING.md) and submit a pull request!_
1084
1096
 
1085
1097
  ### How to Contribute
1086
1098
 
1087
1099
  1. **Fork** the repository on GitHub
1088
- 2. **Clone** your fork locally: `git clone https://github.com/yourusername/x-cli-hurry-mode.git`
1100
+ 2. **Clone** your fork locally: `git clone https://github.com/yourusername/x-cli.git`
1089
1101
  3. **Create** a feature branch: `git checkout -b feature/your-feature-name`
1090
1102
  4. **Make** your changes and commit them: `git commit -m "feat: add awesome feature"`
1091
1103
  5. **Push** to your fork: `git push origin feature/your-feature-name`
@@ -1102,3 +1114,5 @@ _Want to see your name here? Check out our [Contributing Guide](CONTRIBUTING.md)
1102
1114
  - 💡 **Feature requests** - Suggest new functionality
1103
1115
 
1104
1116
  Join our growing community of AI-powered terminal enthusiasts!
1117
+
1118
+ # Test: Branch Protection Rules Test
package/dist/index.js CHANGED
@@ -7039,10 +7039,10 @@ var DependencyAnalyzerTool = class {
7039
7039
  const circularDeps = [];
7040
7040
  const visited = /* @__PURE__ */ new Set();
7041
7041
  const visiting = /* @__PURE__ */ new Set();
7042
- const dfs = (filePath, path30) => {
7042
+ const dfs = (filePath, path31) => {
7043
7043
  if (visiting.has(filePath)) {
7044
- const cycleStart = path30.indexOf(filePath);
7045
- const cycle = path30.slice(cycleStart).concat([filePath]);
7044
+ const cycleStart = path31.indexOf(filePath);
7045
+ const cycle = path31.slice(cycleStart).concat([filePath]);
7046
7046
  circularDeps.push({
7047
7047
  cycle: cycle.map((fp) => graph.nodes.get(fp)?.filePath || fp),
7048
7048
  severity: cycle.length <= 2 ? "error" : "warning",
@@ -7058,7 +7058,7 @@ var DependencyAnalyzerTool = class {
7058
7058
  if (node) {
7059
7059
  for (const dependency of node.dependencies) {
7060
7060
  if (graph.nodes.has(dependency)) {
7061
- dfs(dependency, [...path30, filePath]);
7061
+ dfs(dependency, [...path31, filePath]);
7062
7062
  }
7063
7063
  }
7064
7064
  }
@@ -9030,10 +9030,10 @@ Current working directory: ${process.cwd()}`
9030
9030
  return await this.textEditor.view(args.path, range);
9031
9031
  } catch (error) {
9032
9032
  console.warn(`view_file tool failed, falling back to bash: ${error.message}`);
9033
- const path30 = args.path;
9034
- let command = `cat "${path30}"`;
9033
+ const path31 = args.path;
9034
+ let command = `cat "${path31}"`;
9035
9035
  if (args.start_line && args.end_line) {
9036
- command = `sed -n '${args.start_line},${args.end_line}p' "${path30}"`;
9036
+ command = `sed -n '${args.start_line},${args.end_line}p' "${path31}"`;
9037
9037
  }
9038
9038
  return await this.bash.execute(command);
9039
9039
  }
@@ -14655,7 +14655,7 @@ ${guardrail.createdFrom ? `- Created from incident: ${guardrail.createdFrom}` :
14655
14655
  var package_default = {
14656
14656
  type: "module",
14657
14657
  name: "@xagent/x-cli",
14658
- version: "1.1.67",
14658
+ version: "1.1.69",
14659
14659
  description: "An open-source AI agent that brings the power of Grok directly into your terminal.",
14660
14660
  main: "dist/index.js",
14661
14661
  module: "dist/index.js",
@@ -14684,6 +14684,7 @@ var package_default = {
14684
14684
  "dev:watch": "npm run build && node --watch dist/index.js",
14685
14685
  start: "node dist/index.js",
14686
14686
  local: "npm run build && npm link && node dist/index.js",
14687
+ "test:workflow": "node scripts/test-workflow.js",
14687
14688
  "start:bun": "bun run dist/index.js",
14688
14689
  lint: "eslint . --ext .js,.jsx,.ts,.tsx",
14689
14690
  typecheck: "tsc --noEmit",
@@ -16501,23 +16502,109 @@ ${commitMessage}`
16501
16502
  setChatHistory((prev) => [...prev, commitEntry]);
16502
16503
  if (commitResult.success) {
16503
16504
  const pushResult = await agent.executeBashCommand("git push");
16504
- const pushEntry = {
16505
- type: "tool_result",
16506
- content: pushResult.success ? `\u{1F680} **Push Successful**: ${pushResult.output?.split("\n")[0] || "Changes pushed to remote"}` : `\u274C **Push Failed**: ${pushResult.error || "Unknown error"}
16505
+ if (pushResult.success) {
16506
+ const pushEntry = {
16507
+ type: "tool_result",
16508
+ content: `\u{1F680} **Push Successful**: ${pushResult.output?.split("\n")[0] || "Changes pushed to remote"}`,
16509
+ timestamp: /* @__PURE__ */ new Date(),
16510
+ toolCall: {
16511
+ id: `git_push_${Date.now()}`,
16512
+ type: "function",
16513
+ function: {
16514
+ name: "bash",
16515
+ arguments: JSON.stringify({ command: "git push" })
16516
+ }
16517
+ },
16518
+ toolResult: pushResult
16519
+ };
16520
+ setChatHistory((prev) => [...prev, pushEntry]);
16521
+ } else {
16522
+ const pushError = pushResult.error || pushResult.output || "";
16523
+ if (pushError.includes("protected branch") || pushError.includes("Changes must be made through a pull request") || pushError.includes("GH006")) {
16524
+ const branchProtectionEntry = {
16525
+ type: "assistant",
16526
+ content: "\u{1F6E1}\uFE0F **Branch Protection Detected**: Direct pushes to this branch are blocked.\n\n\u{1F504} **Creating PR workflow...**",
16527
+ timestamp: /* @__PURE__ */ new Date()
16528
+ };
16529
+ setChatHistory((prev) => [...prev, branchProtectionEntry]);
16530
+ const featureBranch = `feature/${(/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace(/[:-]/g, "").replace("T", "-")}-smart-push`;
16531
+ const createBranchResult = await agent.executeBashCommand(`git checkout -b ${featureBranch}`);
16532
+ if (createBranchResult.success) {
16533
+ const pushBranchResult = await agent.executeBashCommand(`git push -u origin ${featureBranch}`);
16534
+ if (pushBranchResult.success) {
16535
+ const branchSuccessEntry = {
16536
+ type: "tool_result",
16537
+ content: `\u2705 **Feature Branch Created**: \`${featureBranch}\`
16538
+
16539
+ \u{1F4CB} **Attempting to create Pull Request...**`,
16540
+ timestamp: /* @__PURE__ */ new Date()
16541
+ };
16542
+ setChatHistory((prev) => [...prev, branchSuccessEntry]);
16543
+ const prResult = await agent.executeBashCommand(`gh pr create --title "${cleanCommitMessage}" --body "Auto-generated PR from smart-push" --head ${featureBranch} --base main`);
16544
+ if (prResult.success) {
16545
+ const prUrl = prResult.output?.match(/https:\/\/github\.com\/[^\s]+/)?.[0];
16546
+ const prSuccessEntry = {
16547
+ type: "tool_result",
16548
+ content: `\u2705 **Pull Request Created Successfully!**
16507
16549
 
16508
- Try running \`git push\` manually.`,
16509
- timestamp: /* @__PURE__ */ new Date(),
16510
- toolCall: {
16511
- id: `git_push_${Date.now()}`,
16512
- type: "function",
16513
- function: {
16514
- name: "bash",
16515
- arguments: JSON.stringify({ command: "git push" })
16550
+ \u{1F517} **PR URL**: ${prUrl || "Check GitHub for the link"}
16551
+
16552
+ \u{1F3AF} **Next Steps**:
16553
+ \u2022 Review the PR on GitHub
16554
+ \u2022 Wait for CI checks to pass
16555
+ \u2022 Request approval and merge`,
16556
+ timestamp: /* @__PURE__ */ new Date()
16557
+ };
16558
+ setChatHistory((prev) => [...prev, prSuccessEntry]);
16559
+ } else {
16560
+ const prManualEntry = {
16561
+ type: "assistant",
16562
+ content: `\u26A0\uFE0F **PR Creation Failed**: GitHub CLI may not be available.
16563
+
16564
+ \u{1F4A1} **Create PR Manually**:
16565
+ \u2022 Go to GitHub repository
16566
+ \u2022 Create PR from \`${featureBranch}\` \u2192 \`main\`
16567
+ \u2022 Title: \`${cleanCommitMessage}\``,
16568
+ timestamp: /* @__PURE__ */ new Date()
16569
+ };
16570
+ setChatHistory((prev) => [...prev, prManualEntry]);
16571
+ }
16572
+ } else {
16573
+ const pushFailEntry = {
16574
+ type: "tool_result",
16575
+ content: `\u274C **Failed to push feature branch**: ${pushBranchResult.error}`,
16576
+ timestamp: /* @__PURE__ */ new Date()
16577
+ };
16578
+ setChatHistory((prev) => [...prev, pushFailEntry]);
16579
+ }
16580
+ } else {
16581
+ const branchFailEntry = {
16582
+ type: "tool_result",
16583
+ content: `\u274C **Failed to create feature branch**: ${createBranchResult.error}`,
16584
+ timestamp: /* @__PURE__ */ new Date()
16585
+ };
16586
+ setChatHistory((prev) => [...prev, branchFailEntry]);
16516
16587
  }
16517
- },
16518
- toolResult: pushResult
16519
- };
16520
- setChatHistory((prev) => [...prev, pushEntry]);
16588
+ } else {
16589
+ const pushFailEntry = {
16590
+ type: "tool_result",
16591
+ content: `\u274C **Push Failed**: ${pushResult.error || "Unknown error"}
16592
+
16593
+ Try running \`git push\` manually.`,
16594
+ timestamp: /* @__PURE__ */ new Date(),
16595
+ toolCall: {
16596
+ id: `git_push_${Date.now()}`,
16597
+ type: "function",
16598
+ function: {
16599
+ name: "bash",
16600
+ arguments: JSON.stringify({ command: "git push" })
16601
+ }
16602
+ },
16603
+ toolResult: pushResult
16604
+ };
16605
+ setChatHistory((prev) => [...prev, pushFailEntry]);
16606
+ }
16607
+ }
16521
16608
  }
16522
16609
  } catch (error) {
16523
16610
  const errorEntry = {
@@ -19311,6 +19398,119 @@ function createMCPCommand() {
19311
19398
  });
19312
19399
  return mcpCommand;
19313
19400
  }
19401
+ var CONTEXT_BUDGET_BYTES = 280 * 1024;
19402
+ var MAX_SUMMARY_LENGTH = 2e3;
19403
+ function loadMarkdownDirectory(dirPath) {
19404
+ if (!fs__default.existsSync(dirPath)) {
19405
+ return "";
19406
+ }
19407
+ const files = fs__default.readdirSync(dirPath).filter((file) => file.endsWith(".md")).sort();
19408
+ let content = "";
19409
+ for (const file of files) {
19410
+ const filePath = path7__default.join(dirPath, file);
19411
+ try {
19412
+ const fileContent = fs__default.readFileSync(filePath, "utf-8");
19413
+ content += `
19414
+
19415
+ === ${file} ===
19416
+
19417
+ ${fileContent}`;
19418
+ } catch (error) {
19419
+ console.warn(`Failed to read ${filePath}:`, error);
19420
+ }
19421
+ }
19422
+ return content;
19423
+ }
19424
+ function extractDateFromFilename(filename) {
19425
+ const match = filename.match(/^(\d{4}-\d{2}-\d{2})/);
19426
+ if (match) {
19427
+ return new Date(match[1]);
19428
+ }
19429
+ return /* @__PURE__ */ new Date(0);
19430
+ }
19431
+ function summarizeContent(content, maxLength = MAX_SUMMARY_LENGTH) {
19432
+ if (content.length <= maxLength) {
19433
+ return content;
19434
+ }
19435
+ const truncated = content.substring(0, maxLength);
19436
+ const lastNewline = truncated.lastIndexOf("\n\n");
19437
+ if (lastNewline > maxLength * 0.8) {
19438
+ return truncated.substring(0, lastNewline);
19439
+ }
19440
+ return truncated + "\n\n[...content truncated for context budget...]";
19441
+ }
19442
+ function loadTaskFiles(tasksDir, maxBudget) {
19443
+ if (!fs__default.existsSync(tasksDir)) {
19444
+ return [];
19445
+ }
19446
+ const files = fs__default.readdirSync(tasksDir).filter((file) => file.endsWith(".md")).map((filename) => {
19447
+ const filePath = path7__default.join(tasksDir, filename);
19448
+ const content = fs__default.readFileSync(filePath, "utf-8");
19449
+ return {
19450
+ filename,
19451
+ content,
19452
+ size: Buffer.byteLength(content, "utf-8"),
19453
+ date: extractDateFromFilename(filename),
19454
+ isSummarized: false
19455
+ };
19456
+ }).sort((a, b) => b.date.getTime() - a.date.getTime());
19457
+ const result = [];
19458
+ let usedBudget = 0;
19459
+ for (const file of files) {
19460
+ let finalContent = file.content;
19461
+ let isSummarized = false;
19462
+ if (usedBudget + file.size > maxBudget) {
19463
+ finalContent = summarizeContent(file.content);
19464
+ const summarizedSize = Buffer.byteLength(finalContent, "utf-8");
19465
+ if (usedBudget + summarizedSize > maxBudget) {
19466
+ continue;
19467
+ }
19468
+ usedBudget += summarizedSize;
19469
+ isSummarized = true;
19470
+ } else {
19471
+ usedBudget += file.size;
19472
+ }
19473
+ result.push({
19474
+ ...file,
19475
+ content: finalContent,
19476
+ isSummarized
19477
+ });
19478
+ }
19479
+ return result;
19480
+ }
19481
+ function loadContext(agentDir = ".agent") {
19482
+ const systemContent = loadMarkdownDirectory(path7__default.join(agentDir, "system"));
19483
+ const sopContent = loadMarkdownDirectory(path7__default.join(agentDir, "sop"));
19484
+ const systemSize = Buffer.byteLength(systemContent, "utf-8");
19485
+ const sopSize = Buffer.byteLength(sopContent, "utf-8");
19486
+ const taskBudget = Math.max(0, CONTEXT_BUDGET_BYTES - systemSize - sopSize);
19487
+ const tasks = loadTaskFiles(path7__default.join(agentDir, "tasks"), taskBudget);
19488
+ const totalSize = systemSize + sopSize + tasks.reduce((sum, task) => sum + Buffer.byteLength(task.content, "utf-8"), 0);
19489
+ const warnings = [];
19490
+ if (totalSize > CONTEXT_BUDGET_BYTES) {
19491
+ warnings.push(`Context size (${(totalSize / 1024).toFixed(1)}KB) exceeds budget (${CONTEXT_BUDGET_BYTES / 1024}KB)`);
19492
+ }
19493
+ return {
19494
+ system: systemContent,
19495
+ sop: sopContent,
19496
+ tasks,
19497
+ totalSize,
19498
+ warnings
19499
+ };
19500
+ }
19501
+ function formatContextStatus(pack) {
19502
+ const taskCount = pack.tasks.length;
19503
+ const summarizedCount = pack.tasks.filter((t) => t.isSummarized).length;
19504
+ const sizeKB = (pack.totalSize / 1024).toFixed(1);
19505
+ let status = `[x-cli] Context: loaded system docs, sop docs, ${taskCount} task docs (~${sizeKB} KB).`;
19506
+ if (summarizedCount > 0) {
19507
+ status += ` Summarized ${summarizedCount} older tasks for context budget.`;
19508
+ }
19509
+ if (pack.warnings.length > 0) {
19510
+ status += ` Warnings: ${pack.warnings.join("; ")}`;
19511
+ }
19512
+ return status;
19513
+ }
19314
19514
 
19315
19515
  // src/index.ts
19316
19516
  dotenv.config();
@@ -19603,6 +19803,15 @@ program.name("grok").description(
19603
19803
  if (!options.quiet) {
19604
19804
  console.log("\u{1F916} Starting X CLI Conversational Assistant...\n");
19605
19805
  }
19806
+ if (!options.quiet) {
19807
+ try {
19808
+ const contextPack = loadContext();
19809
+ const statusMessage = formatContextStatus(contextPack);
19810
+ console.log(statusMessage);
19811
+ } catch (error) {
19812
+ console.warn("\u26A0\uFE0F Failed to load .agent/ context:", error instanceof Error ? error.message : String(error));
19813
+ }
19814
+ }
19606
19815
  ensureUserSettingsDirectory();
19607
19816
  checkAutoCompact();
19608
19817
  checkStartupUpdates();