@neurynae/toolcairn-mcp 0.10.3 → 0.10.4

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
@@ -4931,7 +4931,45 @@ async function runPostAuthInit(options = {}) {
4931
4931
  });
4932
4932
  }
4933
4933
  }
4934
- const unknownTotal = projects.reduce((sum, p) => sum + (p.unknown_tools?.length ?? 0), 0);
4934
+ if (!options.disableAutoSubmit) {
4935
+ for (const project of projects) {
4936
+ if (project.status !== "initialized") continue;
4937
+ const pending = (project.unknown_tools ?? []).filter((t) => !!t.github_url);
4938
+ if (pending.length === 0) continue;
4939
+ try {
4940
+ const outcome = await submitUnknownsToEngine(remote, pending);
4941
+ project.auto_submitted = outcome;
4942
+ const toMark = [...outcome.staged, ...outcome.already_staged, ...outcome.already_indexed];
4943
+ if (toMark.length > 0) {
4944
+ await markSuggestedInConfig(project.project_root, toMark).catch(
4945
+ (err) => logger22.warn(
4946
+ { err, projectRoot: project.project_root },
4947
+ "Failed to flip suggested flags after auto-submit"
4948
+ )
4949
+ );
4950
+ }
4951
+ logger22.info(
4952
+ {
4953
+ projectRoot: project.project_root,
4954
+ staged: outcome.staged.length,
4955
+ already_staged: outcome.already_staged.length,
4956
+ already_indexed: outcome.already_indexed.length,
4957
+ rejected: outcome.rejected.length
4958
+ },
4959
+ "Auto-push to suggest_graph_update complete"
4960
+ );
4961
+ } catch (err) {
4962
+ logger22.warn(
4963
+ { err, projectRoot: project.project_root },
4964
+ "Auto-push to suggest_graph_update failed \u2014 agent directive remains as fallback"
4965
+ );
4966
+ }
4967
+ }
4968
+ }
4969
+ const unknownTotal = projects.reduce(
4970
+ (sum, p) => sum + (p.unknown_tools ?? []).filter((t) => !t.suggested).length,
4971
+ 0
4972
+ );
4935
4973
  const directive = buildFirstTurnDirective(projects, unknownTotal);
4936
4974
  return {
4937
4975
  cwd,
@@ -4942,19 +4980,87 @@ async function runPostAuthInit(options = {}) {
4942
4980
  first_turn_directive: directive
4943
4981
  };
4944
4982
  }
4983
+ async function submitUnknownsToEngine(remote, pending) {
4984
+ const res = await remote.suggestGraphUpdate({
4985
+ suggestion_type: "new_tool",
4986
+ data: {
4987
+ tools: pending.map((t) => ({ tool_name: t.name, github_url: t.github_url }))
4988
+ },
4989
+ confidence: 0.5
4990
+ });
4991
+ const textBlock = res.content?.[0];
4992
+ const outcome = {
4993
+ staged: [],
4994
+ already_staged: [],
4995
+ already_indexed: [],
4996
+ rejected: []
4997
+ };
4998
+ if (!textBlock || textBlock.type !== "text") return outcome;
4999
+ let envelope;
5000
+ try {
5001
+ envelope = JSON.parse(textBlock.text ?? "{}");
5002
+ } catch {
5003
+ return outcome;
5004
+ }
5005
+ const items = envelope.data?.results ?? [];
5006
+ for (const item of items) {
5007
+ const name = item.tool_name ?? "";
5008
+ if (!name) continue;
5009
+ if (item.already_indexed) {
5010
+ outcome.already_indexed.push(name);
5011
+ } else if (item.already_staged) {
5012
+ outcome.already_staged.push(name);
5013
+ } else if (item.staged === true) {
5014
+ outcome.staged.push(name);
5015
+ } else {
5016
+ outcome.rejected.push({ tool_name: name, reason: item.reason ?? "unknown" });
5017
+ }
5018
+ }
5019
+ return outcome;
5020
+ }
5021
+ async function markSuggestedInConfig(projectRoot, toolNames) {
5022
+ const wanted = new Set(toolNames);
5023
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5024
+ let changed = 0;
5025
+ await mutateConfig(
5026
+ projectRoot,
5027
+ (cfg) => {
5028
+ const list = cfg.tools.unknown_in_graph ?? [];
5029
+ for (const entry of list) {
5030
+ if (wanted.has(entry.name) && !entry.suggested) {
5031
+ entry.suggested = true;
5032
+ entry.suggested_at = now;
5033
+ changed++;
5034
+ }
5035
+ }
5036
+ cfg.tools.unknown_in_graph = list;
5037
+ },
5038
+ {
5039
+ action: "mark_suggestions_sent",
5040
+ tool: `__auto_submit__:${toolNames.length}`,
5041
+ reason: "Server auto-pushed unknown_in_graph tools to suggest_graph_update"
5042
+ }
5043
+ );
5044
+ if (changed === 0) {
5045
+ logger22.debug({ projectRoot, toolNames }, "No unknown_in_graph entries flipped");
5046
+ }
5047
+ }
4945
5048
  function buildFirstTurnDirective(projects, unknownTotal) {
4946
5049
  if (unknownTotal === 0) return "";
4947
- const rootsWithUnknown = projects.filter((p) => (p.unknown_tools?.length ?? 0) > 0);
5050
+ const rootsWithUnknown = projects.filter(
5051
+ (p) => (p.unknown_tools ?? []).filter((t) => !t.suggested).length > 0
5052
+ );
5053
+ if (rootsWithUnknown.length === 0) return "";
4948
5054
  const roots = rootsWithUnknown.map((p) => p.project_root).join(", ");
4949
5055
  return [
4950
5056
  `The auto-init scan found ${unknownTotal} tool(s) not yet in the ToolCairn graph`,
4951
5057
  `across ${rootsWithUnknown.length} project root(s): ${roots}.`,
4952
- "BEFORE responding to the user, for EACH root with a non-empty `unknown_tools[]`:",
5058
+ "The server has already auto-submitted these to the admin review queue,",
5059
+ "but you MAY repeat the call below to confirm \u2014 engine-side dedup prevents duplicates:",
4953
5060
  '(1) call `suggest_graph_update` with suggestion_type="new_tool" and',
4954
- " data.tools=<that root's unknown_tools array> \u2014 entries will be STAGED",
4955
- " for admin review (no live-graph writes yet);",
5061
+ " data.tools=<that root's unknown_tools array>;",
4956
5062
  '(2) call `update_project_config` with action="mark_suggestions_sent",',
4957
- " project_root, and data.tool_names=<names that staged successfully>."
5063
+ " project_root, and data.tool_names=<names that staged or were already_staged>."
4958
5064
  ].join(" ");
4959
5065
  }
4960
5066