@neurynae/toolcairn-mcp 0.10.4 → 0.10.5

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/dist/index.js CHANGED
@@ -923,7 +923,7 @@ async function pollForToken(apiUrl, deviceCode, intervalSec) {
923
923
  }
924
924
  }
925
925
  function sleep(ms) {
926
- return new Promise((resolve3) => setTimeout(resolve3, ms));
926
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
927
927
  }
928
928
 
929
929
  // src/index.prod.ts
@@ -1165,6 +1165,9 @@ var import_errors21 = __toESM(require_dist2(), 1);
1165
1165
  // ../../packages/tools-local/dist/auto-init.js
1166
1166
  init_esm_shims();
1167
1167
  var import_errors20 = __toESM(require_dist2(), 1);
1168
+ import { readFile as readFile28 } from "fs/promises";
1169
+ import { resolve as resolve3 } from "path";
1170
+ import writeFileAtomic3 from "write-file-atomic";
1168
1171
 
1169
1172
  // ../../packages/tools-local/dist/config-store/index.js
1170
1173
  init_esm_shims();
@@ -4481,6 +4484,9 @@ function getOpenCodeMcpEntry(serverPath) {
4481
4484
 
4482
4485
  // ../../packages/tools-local/dist/auto-init.js
4483
4486
  var logger18 = (0, import_errors20.createMcpLogger)({ name: "@toolcairn/tools:auto-init" });
4487
+ var INSTRUCTION_SENTINEL = "## ToolCairn \u2014 Tool Intelligence MCP";
4488
+ var GITIGNORE_SENTINEL = "# ToolCairn";
4489
+ var GITIGNORE_BLOCK = "\n# ToolCairn\n.toolcairn/events.jsonl\n.toolcairn/audit-log.jsonl\n.toolcairn/audit-log.archive.jsonl\n.toolcairn/config.lock\n";
4484
4490
  async function autoInitProject(input) {
4485
4491
  const { projectRoot, agent, batchResolve, serverPath, reason } = input;
4486
4492
  logger18.info({ projectRoot, agent }, "autoInitProject starting");
@@ -4546,10 +4552,23 @@ async function autoInitProject(input) {
4546
4552
  step: 3,
4547
4553
  action: "append",
4548
4554
  file: ".gitignore",
4549
- content: "\n# ToolCairn\n.toolcairn/events.jsonl\n.toolcairn/audit-log.jsonl\n.toolcairn/audit-log.archive.jsonl\n.toolcairn/config.lock\n",
4555
+ content: GITIGNORE_BLOCK,
4550
4556
  note: "Ignore runtime/audit files. config.json should be committed so teammates share tool intelligence."
4551
4557
  }
4552
4558
  ];
4559
+ const applied_steps = input.skipSetupFileWrites ? setupSteps.map((s) => ({
4560
+ file: s.file,
4561
+ action: s.action,
4562
+ applied: false,
4563
+ reason: "skipSetupFileWrites=true"
4564
+ })) : await applySetupFiles(projectRoot, {
4565
+ agent,
4566
+ instructionFile: instructions.file_path,
4567
+ instructionContent: instructions.content,
4568
+ mcpConfigFile,
4569
+ mcpConfigEntry,
4570
+ isOpenCode
4571
+ });
4553
4572
  const tool_counts = {
4554
4573
  total: config5.tools.confirmed.length,
4555
4574
  indexed: config5.tools.confirmed.filter((t) => t.source === "toolcairn").length,
@@ -4564,6 +4583,7 @@ async function autoInitProject(input) {
4564
4583
  events_path: ".toolcairn/events.jsonl",
4565
4584
  mcp_config_entry: mcpConfigEntry,
4566
4585
  setup_steps: setupSteps,
4586
+ applied_steps,
4567
4587
  scan_summary: {
4568
4588
  project_name: scan.name,
4569
4589
  languages: scan.languages.map((l) => ({ name: l.name, file_count: l.file_count })),
@@ -4579,6 +4599,108 @@ async function autoInitProject(input) {
4579
4599
  unknown_tools: undrained
4580
4600
  };
4581
4601
  }
4602
+ async function applySetupFiles(projectRoot, args) {
4603
+ const results = [];
4604
+ results.push(await applyInstructionFile(resolve3(projectRoot, args.instructionFile), args.instructionFile, args.instructionContent));
4605
+ results.push(await applyMcpConfig(resolve3(projectRoot, args.mcpConfigFile), args.mcpConfigFile, args.mcpConfigEntry, args.isOpenCode));
4606
+ results.push(await applyGitignore(resolve3(projectRoot, ".gitignore")));
4607
+ return results;
4608
+ }
4609
+ async function applyInstructionFile(abs, relPath, content) {
4610
+ try {
4611
+ const exists = await fileExists(abs);
4612
+ if (exists) {
4613
+ const current = await readFile28(abs, "utf-8");
4614
+ if (current.includes(INSTRUCTION_SENTINEL)) {
4615
+ return {
4616
+ file: relPath,
4617
+ action: "append-or-create",
4618
+ applied: false,
4619
+ reason: "ToolCairn rules block already present"
4620
+ };
4621
+ }
4622
+ const separator = current.endsWith("\n") ? "" : "\n";
4623
+ await writeFileAtomic3(abs, `${current}${separator}${content}`, "utf-8");
4624
+ return { file: relPath, action: "append-or-create", applied: true };
4625
+ }
4626
+ await writeFileAtomic3(abs, content, "utf-8");
4627
+ return { file: relPath, action: "append-or-create", applied: true };
4628
+ } catch (err) {
4629
+ const reason = err instanceof Error ? err.message : String(err);
4630
+ logger18.warn({ err, file: relPath }, "Failed to write instruction file");
4631
+ return { file: relPath, action: "append-or-create", applied: false, reason };
4632
+ }
4633
+ }
4634
+ async function applyMcpConfig(abs, relPath, entry, isOpenCode) {
4635
+ try {
4636
+ const exists = await fileExists(abs);
4637
+ const topKey = isOpenCode ? "mcp" : "mcpServers";
4638
+ if (!exists) {
4639
+ const payload = { [topKey]: entry };
4640
+ await writeFileAtomic3(abs, `${JSON.stringify(payload, null, 2)}
4641
+ `, "utf-8");
4642
+ return { file: relPath, action: "merge-or-create", applied: true };
4643
+ }
4644
+ const raw = await readFile28(abs, "utf-8");
4645
+ let parsed;
4646
+ try {
4647
+ parsed = JSON.parse(raw);
4648
+ } catch {
4649
+ return {
4650
+ file: relPath,
4651
+ action: "merge-or-create",
4652
+ applied: false,
4653
+ reason: "existing file is not valid JSON \u2014 refusing to overwrite; fix manually"
4654
+ };
4655
+ }
4656
+ const existingServers = parsed[topKey] && typeof parsed[topKey] === "object" && !Array.isArray(parsed[topKey]) ? parsed[topKey] : {};
4657
+ if (existingServers.toolcairn !== void 0) {
4658
+ return {
4659
+ file: relPath,
4660
+ action: "merge-or-create",
4661
+ applied: false,
4662
+ reason: `${topKey}.toolcairn already present`
4663
+ };
4664
+ }
4665
+ const merged = {
4666
+ ...parsed,
4667
+ [topKey]: { ...existingServers, ...entry }
4668
+ };
4669
+ await writeFileAtomic3(abs, `${JSON.stringify(merged, null, 2)}
4670
+ `, "utf-8");
4671
+ return { file: relPath, action: "merge-or-create", applied: true };
4672
+ } catch (err) {
4673
+ const reason = err instanceof Error ? err.message : String(err);
4674
+ logger18.warn({ err, file: relPath }, "Failed to write MCP config");
4675
+ return { file: relPath, action: "merge-or-create", applied: false, reason };
4676
+ }
4677
+ }
4678
+ async function applyGitignore(abs) {
4679
+ const relPath = ".gitignore";
4680
+ try {
4681
+ const exists = await fileExists(abs);
4682
+ if (!exists) {
4683
+ await writeFileAtomic3(abs, GITIGNORE_BLOCK.replace(/^\n/, ""), "utf-8");
4684
+ return { file: relPath, action: "append", applied: true };
4685
+ }
4686
+ const current = await readFile28(abs, "utf-8");
4687
+ if (current.includes(GITIGNORE_SENTINEL)) {
4688
+ return {
4689
+ file: relPath,
4690
+ action: "append",
4691
+ applied: false,
4692
+ reason: "ToolCairn gitignore block already present"
4693
+ };
4694
+ }
4695
+ const separator = current.endsWith("\n") ? "" : "\n";
4696
+ await writeFileAtomic3(abs, `${current}${separator}${GITIGNORE_BLOCK}`, "utf-8");
4697
+ return { file: relPath, action: "append", applied: true };
4698
+ } catch (err) {
4699
+ const reason = err instanceof Error ? err.message : String(err);
4700
+ logger18.warn({ err, file: relPath }, "Failed to write .gitignore");
4701
+ return { file: relPath, action: "append", applied: false, reason };
4702
+ }
4703
+ }
4582
4704
 
4583
4705
  // ../../packages/tools-local/dist/handlers/toolcairn-init.js
4584
4706
  var logger19 = (0, import_errors21.createMcpLogger)({ name: "@toolcairn/tools:toolcairn-init" });