@nick848/fet 1.0.7 → 1.0.8

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/cli/index.js CHANGED
@@ -262,7 +262,7 @@ async function doctorCommand(ctx, options = {}) {
262
262
  checks.push(await checkState(ctx));
263
263
  checks.push(await checkFile("agents", join6(ctx.projectRoot, "AGENTS.md"), "AGENTS.md \u7F3A\u5931", "fet update-context"));
264
264
  checks.push(await checkFile("config", join6(ctx.projectRoot, "openspec", "config.yaml"), "openspec/config.yaml \u7F3A\u5931", "fet init"));
265
- checks.push(await checkPlaceholders(ctx.projectRoot));
265
+ checks.push(await checkPlaceholders(ctx));
266
266
  checks.push(await checkGitNexus(ctx));
267
267
  for (const adapter of ctx.toolAdapters) {
268
268
  checks.push(...await adapter.doctor(ctx.projectRoot));
@@ -299,12 +299,12 @@ async function checkGitNexus(ctx) {
299
299
  return state.installed ? {
300
300
  id: "gitnexus",
301
301
  status: "pass",
302
- message: `GitNexus detected: ${state.executablePath ?? "gitnexus"} (${state.version ?? "unknown"}), graph ${state.graphExists ? "found" : "not found"}`
302
+ message: ctx.language === "en" ? `GitNexus detected: ${state.executablePath ?? "gitnexus"} (${state.version ?? "unknown"}), graph ${state.graphExists ? "found" : "not found"}` : `\u68C0\u6D4B\u5230 GitNexus\uFF1A${state.executablePath ?? "gitnexus"}\uFF08${state.version ?? "unknown"}\uFF09\uFF0C\u4EE3\u7801\u56FE${state.graphExists ? "\u5DF2\u627E\u5230" : "\u672A\u627E\u5230"}`
303
303
  } : {
304
304
  id: "gitnexus",
305
305
  status: "warn",
306
- message: "Optional GitNexus code graph support is not installed",
307
- suggestedCommand: "Install GitNexus later if you want OpenSpec artifacts to prefer a repository graph"
306
+ message: ctx.language === "en" ? "Optional GitNexus code graph support is not installed" : "\u5C1A\u672A\u5B89\u88C5\u53EF\u9009\u7684 GitNexus \u4EE3\u7801\u56FE\u652F\u6301",
307
+ suggestedCommand: ctx.language === "en" ? "Install GitNexus later if you want OpenSpec artifacts to prefer a repository graph" : "\u5982\u679C\u5E0C\u671B OpenSpec \u4EA7\u7269\u4F18\u5148\u53C2\u8003\u4ED3\u5E93\u4EE3\u7801\u56FE\uFF0C\u53EF\u4EE5\u7A0D\u540E\u5B89\u88C5 GitNexus"
308
308
  };
309
309
  }
310
310
  async function checkOpenSpec(ctx) {
@@ -326,18 +326,27 @@ async function checkState(ctx) {
326
326
  async function checkFile(id, path, missing, suggestedCommand) {
327
327
  return await exists(path) ? { id, status: "pass", message: `${id} \u5B58\u5728` } : { id, status: "warn", message: missing, suggestedCommand };
328
328
  }
329
- async function checkPlaceholders(projectRoot) {
329
+ async function checkPlaceholders(ctx) {
330
330
  try {
331
- await readFile4(join6(projectRoot, "AGENTS.md"), "utf8");
332
- const count2 = await countAgentsLlmPlaceholders(projectRoot);
331
+ await readFile4(join6(ctx.projectRoot, "AGENTS.md"), "utf8");
332
+ const count2 = await countAgentsLlmPlaceholders(ctx.projectRoot);
333
333
  return count2 ? {
334
334
  id: "context-placeholders",
335
335
  status: "warn",
336
- message: `AGENTS.md has ${count2} LLM placeholder(s)`,
336
+ message: ctx.language === "en" ? `AGENTS.md has ${count2} LLM placeholder(s)` : `AGENTS.md \u4ECD\u6709 ${count2} \u4E2A LLM \u5360\u4F4D\u7B26`,
337
337
  suggestedCommand: "fet fill-context"
338
- } : { id: "context-placeholders", status: "pass", message: "AGENTS.md placeholders resolved" };
338
+ } : {
339
+ id: "context-placeholders",
340
+ status: "pass",
341
+ message: ctx.language === "en" ? "AGENTS.md placeholders resolved" : "AGENTS.md \u5360\u4F4D\u7B26\u5DF2\u5904\u7406"
342
+ };
339
343
  } catch {
340
- return { id: "context-placeholders", status: "warn", message: "AGENTS.md missing", suggestedCommand: "fet update-context" };
344
+ return {
345
+ id: "context-placeholders",
346
+ status: "warn",
347
+ message: ctx.language === "en" ? "AGENTS.md missing" : "AGENTS.md \u7F3A\u5931",
348
+ suggestedCommand: "fet update-context"
349
+ };
341
350
  }
342
351
  }
343
352
  async function exists(path) {
@@ -459,38 +468,41 @@ async function graphCommand(ctx, action, args = []) {
459
468
  }
460
469
  async function graphStatusCommand(ctx) {
461
470
  const result = await refreshGraphState(ctx, { runStatus: true });
462
- const warnings = result.state.installed ? [] : ["GitNexus is not installed. Run fet graph setup for installation handoff instructions."];
471
+ const warnings = result.state.installed ? [] : [
472
+ ctx.language === "en" ? "GitNexus is not installed. Run fet graph setup for installation handoff instructions." : "\u5C1A\u672A\u5B89\u88C5 GitNexus\u3002\u8FD0\u884C fet graph setup \u83B7\u53D6\u5B89\u88C5\u4EA4\u63A5\u8BF4\u660E\u3002"
473
+ ];
463
474
  ctx.output.result({
464
475
  ok: true,
465
476
  command: "graph status",
466
- summary: result.state.installed ? `GitNexus graph status checked. Graph ${result.state.graphExists ? "exists" : "does not exist"} at ${result.state.graphPath ?? ".gitnexus"}.` : "GitNexus is not installed. Graph support remains optional.",
477
+ summary: ctx.language === "en" ? result.state.installed ? `GitNexus graph status checked. Graph ${result.state.graphExists ? "exists" : "does not exist"} at ${result.state.graphPath ?? ".gitnexus"}.` : "GitNexus is not installed. Graph support remains optional." : result.state.installed ? `\u5DF2\u68C0\u67E5 GitNexus \u4EE3\u7801\u56FE\u72B6\u6001\u3002\u4EE3\u7801\u56FE${result.state.graphExists ? "\u5B58\u5728" : "\u4E0D\u5B58\u5728"}\uFF0C\u8DEF\u5F84\u4E3A ${result.state.graphPath ?? ".gitnexus"}\u3002` : "\u5C1A\u672A\u5B89\u88C5 GitNexus\u3002\u4EE3\u7801\u56FE\u80FD\u529B\u4FDD\u6301\u53EF\u9009\u3002",
467
478
  warnings,
468
- nextSteps: result.state.installed && !result.state.graphExists ? ["Run fet graph init to build the first GitNexus graph"] : void 0,
479
+ nextSteps: result.state.installed && !result.state.graphExists ? [ctx.language === "en" ? "Run fet graph init to build the first GitNexus graph" : "\u8FD0\u884C fet graph init \u751F\u6210\u7B2C\u4E00\u4EFD GitNexus \u4EE3\u7801\u56FE"] : void 0,
469
480
  data: result
470
481
  });
471
482
  }
472
483
  async function graphDoctorCommand(ctx) {
473
484
  const result = await refreshGraphState(ctx, { runStatus: true });
474
485
  const warnings = [
475
- ...!result.state.installed ? ["GitNexus is not installed."] : [],
476
- ...result.state.installed && !result.state.graphExists ? ["GitNexus is installed but no graph directory was found."] : [],
477
- ...!result.state.handoffPath ? ["Graph handoff instructions have not been generated."] : []
486
+ ...!result.state.installed ? [ctx.language === "en" ? "GitNexus is not installed." : "\u5C1A\u672A\u5B89\u88C5 GitNexus\u3002"] : [],
487
+ ...result.state.installed && !result.state.graphExists ? [ctx.language === "en" ? "GitNexus is installed but no graph directory was found." : "\u5DF2\u5B89\u88C5 GitNexus\uFF0C\u4F46\u672A\u53D1\u73B0\u4EE3\u7801\u56FE\u76EE\u5F55\u3002"] : [],
488
+ ...!result.state.handoffPath ? [ctx.language === "en" ? "Graph handoff instructions have not been generated." : "\u5C1A\u672A\u751F\u6210\u4EE3\u7801\u56FE\u4F7F\u7528\u4EA4\u63A5\u8BF4\u660E\u3002"] : []
478
489
  ];
479
490
  ctx.output.result({
480
491
  ok: true,
481
492
  command: "graph doctor",
482
- summary: warnings.length ? `Graph doctor completed with ${warnings.length} warning(s).` : "Graph doctor completed without warnings.",
493
+ summary: ctx.language === "en" ? warnings.length ? `Graph doctor completed with ${warnings.length} warning(s).` : "Graph doctor completed without warnings." : warnings.length ? `\u4EE3\u7801\u56FE\u8BCA\u65AD\u5B8C\u6210\uFF0C\u53D1\u73B0 ${warnings.length} \u4E2A\u8B66\u544A\u3002` : "\u4EE3\u7801\u56FE\u8BCA\u65AD\u5B8C\u6210\uFF0C\u672A\u53D1\u73B0\u8B66\u544A\u3002",
483
494
  warnings,
484
- nextSteps: warnings.length ? ["Run fet graph setup", "Run fet graph handoff", "Run fet graph init when GitNexus is installed"] : void 0,
495
+ nextSteps: warnings.length ? ctx.language === "en" ? ["Run fet graph setup", "Run fet graph handoff", "Run fet graph init when GitNexus is installed"] : ["\u8FD0\u884C fet graph setup", "\u8FD0\u884C fet graph handoff", "\u5B89\u88C5 GitNexus \u540E\u8FD0\u884C fet graph init"] : void 0,
485
496
  data: result
486
497
  });
487
498
  }
488
499
  async function graphSetupCommand(ctx) {
489
500
  let result;
490
501
  const handoffPath = join8(ctx.projectRoot, ".fet", "graph-setup.md");
502
+ const installCommand = process.env.FET_GITNEXUS_INSTALL_COMMAND?.trim() || null;
491
503
  await withProjectLock(ctx.projectRoot, { command: "graph setup", cwd: ctx.cwd, fetVersion: ctx.fetVersion }, async () => {
492
504
  result = await refreshGraphState(ctx, { write: false });
493
- await writeHandoffFile(handoffPath, renderGraphSetupHandoff(result.state));
505
+ await writeHandoffFile(handoffPath, renderGraphSetupHandoff(result.state, { installCommand, language: ctx.language }));
494
506
  const global = await ctx.stateStore.getOrCreateGlobal();
495
507
  global.graph ??= {};
496
508
  global.graph.gitnexus = {
@@ -503,11 +515,19 @@ async function graphSetupCommand(ctx) {
503
515
  ctx.output.result({
504
516
  ok: true,
505
517
  command: "graph setup",
506
- summary: "GitNexus setup handoff generated.",
507
- warnings: result.state.installed ? [] : ["GitNexus is not installed. The handoff explains installation and IDE-assisted setup options."],
508
- nextSteps: result.state.installed ? ["Run gitnexus setup if you want to configure IDE/MCP integrations", "Run fet graph init"] : ["Open .fet/graph-setup.md in your IDE AI"],
518
+ summary: ctx.language === "en" ? "GitNexus IDE-assisted setup playbook generated." : "\u5DF2\u751F\u6210 GitNexus IDE LLM \u8F85\u52A9\u5B89\u88C5\u4EFB\u52A1\u4E66\u3002",
519
+ warnings: result.state.installed ? [] : [
520
+ ctx.language === "en" ? "GitNexus is not installed. The playbook lets the current IDE LLM guide installation with user confirmation before risky commands." : "\u5C1A\u672A\u5B89\u88C5 GitNexus\u3002\u4EFB\u52A1\u4E66\u4F1A\u6307\u5BFC\u5F53\u524D IDE LLM \u63A8\u8FDB\u5B89\u88C5\uFF0C\u5E76\u5728\u9AD8\u98CE\u9669\u547D\u4EE4\u524D\u8BF7\u6C42\u7528\u6237\u786E\u8BA4\u3002"
521
+ ],
522
+ nextSteps: result.state.installed ? [
523
+ ctx.language === "en" ? "Ask your IDE AI to read .fet/graph-setup.md and run the optional gitnexus setup flow if you want IDE/MCP integration" : "\u8BA9\u5F53\u524D IDE AI \u9605\u8BFB .fet/graph-setup.md\uFF0C\u5E76\u5728\u9700\u8981 IDE/MCP \u96C6\u6210\u65F6\u6309\u786E\u8BA4\u6D41\u7A0B\u8FD0\u884C gitnexus setup",
524
+ "fet graph init"
525
+ ] : [
526
+ ctx.language === "en" ? "Ask your current IDE AI to read .fet/graph-setup.md and follow the installation playbook" : "\u8BA9\u5F53\u524D IDE AI \u9605\u8BFB .fet/graph-setup.md\uFF0C\u5E76\u6309\u5B89\u88C5\u4EFB\u52A1\u4E66\u63A8\u8FDB"
527
+ ],
509
528
  data: {
510
529
  path: ".fet/graph-setup.md",
530
+ installCommandConfigured: Boolean(installCommand),
511
531
  gitnexus: result.state
512
532
  }
513
533
  });
@@ -517,7 +537,7 @@ async function graphHandoffCommand(ctx) {
517
537
  const handoffPath = join8(ctx.projectRoot, ".fet", "graph-handoff.md");
518
538
  await withProjectLock(ctx.projectRoot, { command: "graph handoff", cwd: ctx.cwd, fetVersion: ctx.fetVersion }, async () => {
519
539
  result = await refreshGraphState(ctx, { runStatus: true, write: false });
520
- await writeHandoffFile(handoffPath, renderGraphUsageHandoff(result.state));
540
+ await writeHandoffFile(handoffPath, renderGraphUsageHandoff(result.state, ctx.language));
521
541
  const global = await ctx.stateStore.getOrCreateGlobal();
522
542
  global.graph ??= {};
523
543
  global.graph.gitnexus = {
@@ -530,9 +550,11 @@ async function graphHandoffCommand(ctx) {
530
550
  ctx.output.result({
531
551
  ok: true,
532
552
  command: "graph handoff",
533
- summary: "GitNexus graph usage handoff generated.",
534
- warnings: result.state.installed ? [] : ["GitNexus is not installed. The handoff still documents the fallback behavior."],
535
- nextSteps: ["Cursor/Codex/OpenCode: read .fet/graph-handoff.md before broad repository scans"],
553
+ summary: ctx.language === "en" ? "GitNexus graph usage handoff generated." : "\u5DF2\u751F\u6210 GitNexus \u4EE3\u7801\u56FE\u4F7F\u7528\u4EA4\u63A5\u8BF4\u660E\u3002",
554
+ warnings: result.state.installed ? [] : [
555
+ ctx.language === "en" ? "GitNexus is not installed. The handoff still documents the fallback behavior." : "\u5C1A\u672A\u5B89\u88C5 GitNexus\u3002\u4EA4\u63A5\u8BF4\u660E\u4ECD\u4F1A\u8BB0\u5F55\u56DE\u9000\u884C\u4E3A\u3002"
556
+ ],
557
+ nextSteps: ctx.language === "en" ? ["Cursor/Codex/OpenCode: read .fet/graph-handoff.md before broad repository scans"] : ["Cursor/Codex/OpenCode\uFF1A\u5927\u8303\u56F4\u626B\u63CF\u4ED3\u5E93\u524D\u5148\u9605\u8BFB .fet/graph-handoff.md"],
536
558
  data: {
537
559
  path: ".fet/graph-handoff.md",
538
560
  gitnexus: result.state
@@ -544,7 +566,7 @@ async function graphAnalyzeCommand(ctx, mode, args) {
544
566
  if (!detection.installed) {
545
567
  throw new FetError({
546
568
  code: "GRAPH_PROVIDER_NOT_FOUND" /* GraphProviderNotFound */,
547
- message: "GitNexus is not installed or is not available on PATH.",
569
+ message: ctx.language === "en" ? "GitNexus is not installed or is not available on PATH." : "\u5C1A\u672A\u5B89\u88C5 GitNexus\uFF0C\u6216 GitNexus \u4E0D\u5728 PATH \u4E2D\u3002",
548
570
  details: { executable: detection.executablePath, error: detection.error },
549
571
  suggestedCommand: "fet graph setup"
550
572
  });
@@ -553,7 +575,7 @@ async function graphAnalyzeCommand(ctx, mode, args) {
553
575
  if (run.exitCode !== 0) {
554
576
  throw new FetError({
555
577
  code: "GRAPH_COMMAND_FAILED" /* GraphCommandFailed */,
556
- message: "GitNexus analyze failed.",
578
+ message: ctx.language === "en" ? "GitNexus analyze failed." : "GitNexus analyze \u6267\u884C\u5931\u8D25\u3002",
557
579
  details: { command: run.command.join(" "), exitCode: run.exitCode, stdout: run.stdout, stderr: run.stderr },
558
580
  suggestedCommand: "fet graph doctor"
559
581
  });
@@ -569,9 +591,11 @@ async function graphAnalyzeCommand(ctx, mode, args) {
569
591
  ctx.output.result({
570
592
  ok: true,
571
593
  command: `graph ${mode}`,
572
- summary: mode === "init" ? "GitNexus graph initialized." : "GitNexus graph refreshed.",
573
- warnings: result.state.graphExists ? [] : ["GitNexus analyze completed, but the configured graph directory was not found."],
574
- nextSteps: ["Run fet graph status", "Use .fet/graph-handoff.md or generated IDE prompts to prefer graph context"],
594
+ summary: ctx.language === "en" ? mode === "init" ? "GitNexus graph initialized." : "GitNexus graph refreshed." : mode === "init" ? "\u5DF2\u521D\u59CB\u5316 GitNexus \u4EE3\u7801\u56FE\u3002" : "\u5DF2\u5237\u65B0 GitNexus \u4EE3\u7801\u56FE\u3002",
595
+ warnings: result.state.graphExists ? [] : [
596
+ ctx.language === "en" ? "GitNexus analyze completed, but the configured graph directory was not found." : "GitNexus analyze \u5DF2\u5B8C\u6210\uFF0C\u4F46\u672A\u53D1\u73B0\u914D\u7F6E\u7684\u4EE3\u7801\u56FE\u76EE\u5F55\u3002"
597
+ ],
598
+ nextSteps: ctx.language === "en" ? ["Run fet graph status", "Use .fet/graph-handoff.md or generated IDE prompts to prefer graph context"] : ["\u8FD0\u884C fet graph status", "\u4F7F\u7528 .fet/graph-handoff.md \u6216\u751F\u6210\u7684 IDE \u63D0\u793A\uFF0C\u4F18\u5148\u53C2\u8003\u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587"],
575
599
  data: {
576
600
  gitnexus: global.graph.gitnexus,
577
601
  run: {
@@ -614,15 +638,16 @@ async function writeHandoffFile(path, content) {
614
638
  await mkdir4(dirname5(path), { recursive: true });
615
639
  await atomicWrite(path, content);
616
640
  }
617
- function renderGraphSetupHandoff(state) {
618
- return `<!-- FET:MANAGED
641
+ function renderGraphSetupHandoff(state, options) {
642
+ if (options.language === "en") {
643
+ return `<!-- FET:MANAGED
619
644
  schemaVersion: 1
620
645
  generator: graph-setup
621
646
  FET:END -->
622
647
 
623
- # FET Graph Setup
648
+ # FET GitNexus IDE Setup Playbook
624
649
 
625
- GitNexus graph support is optional. FET does not install GitNexus automatically and does not require graph support for OpenSpec workflows.
650
+ This file is written for the current IDE LLM. Use it to help the user install and verify optional GitNexus graph support. GitNexus is optional; FET/OpenSpec workflows must continue to work when it is unavailable.
626
651
 
627
652
  Current status:
628
653
 
@@ -631,24 +656,70 @@ Current status:
631
656
  - Version: ${state.version ?? "unknown"}
632
657
  - Graph path: ${state.graphPath ?? ".gitnexus"}
633
658
  - Graph exists: ${state.graphExists ? "yes" : "no"}
659
+ - Configured install command: ${options.installCommand ?? "none"}
634
660
 
635
- Suggested setup flow:
661
+ IDE LLM setup flow:
636
662
 
637
- 1. If GitNexus is not installed, install it using the method recommended by the GitNexus project.
638
- 2. If you want GitNexus MCP or IDE integration, run \`gitnexus setup\` yourself after reviewing what it changes.
639
- 3. Return to this project and run \`fet graph init\` to build the first graph.
640
- 4. Run \`fet graph handoff\` so IDE AI can prefer graph context before broad repository scans.
663
+ 1. Check the shell, operating system, package managers, and PATH. Run only read-only detection commands at first.
664
+ 2. Run \`gitnexus --version\` or the executable shown above. If it succeeds, skip installation and continue to verification.
665
+ 3. If GitNexus is missing and \`FET_GITNEXUS_INSTALL_COMMAND\` is configured, explain that command to the user and ask for approval before running it.
666
+ 4. If no install command is configured, find the official GitNexus installation instructions or ask the user for the preferred install method. Do not invent an installer.
667
+ 5. Before running any command that downloads software, installs globally, changes PATH, modifies user home files, or changes IDE/MCP configuration, show the exact command and wait for user approval.
668
+ 6. After installation, verify with \`gitnexus --version\`.
669
+ 7. If the user wants IDE/MCP integration, run \`gitnexus setup\` only after explaining what it may change and receiving approval.
670
+ 8. Return to this project and run \`fet graph init\` to build the first graph.
671
+ 9. Run \`fet graph handoff\` so future IDE AI work can prefer graph context before broad repository scans.
641
672
 
642
673
  Guardrails:
643
674
 
644
675
  - Do not block FET/OpenSpec commands when GitNexus is unavailable.
645
676
  - Do not generate or modify application code during setup.
646
- - Do not run global IDE configuration commands unless the user explicitly approves them.
677
+ - Do not silently install software or modify global/user-level configuration.
678
+ - If installation fails, summarize the failing command, stderr, and the next manual step.
647
679
  `;
648
- }
649
- function renderGraphUsageHandoff(state) {
680
+ }
650
681
  return `<!-- FET:MANAGED
651
682
  schemaVersion: 1
683
+ generator: graph-setup
684
+ FET:END -->
685
+
686
+ # FET GitNexus IDE \u5B89\u88C5\u4EFB\u52A1\u4E66
687
+
688
+ \u672C\u6587\u6863\u5199\u7ED9\u5F53\u524D IDE LLM\u3002\u8BF7\u7528\u5B83\u5E2E\u52A9\u7528\u6237\u5B89\u88C5\u5E76\u9A8C\u8BC1\u53EF\u9009\u7684 GitNexus \u4EE3\u7801\u56FE\u80FD\u529B\u3002GitNexus \u662F\u53EF\u9009\u80FD\u529B\uFF1B\u5373\u4F7F\u4E0D\u53EF\u7528\uFF0CFET/OpenSpec \u4E3B\u6D41\u7A0B\u4E5F\u5FC5\u987B\u7EE7\u7EED\u53EF\u7528\u3002
689
+
690
+ \u5F53\u524D\u72B6\u6001\uFF1A
691
+
692
+ - \u5DF2\u5B89\u88C5\uFF1A${state.installed ? "\u662F" : "\u5426"}
693
+ - \u53EF\u6267\u884C\u6587\u4EF6\uFF1A${state.executablePath ?? "gitnexus"}
694
+ - \u7248\u672C\uFF1A${state.version ?? "unknown"}
695
+ - \u56FE\u8DEF\u5F84\uFF1A${state.graphPath ?? ".gitnexus"}
696
+ - \u56FE\u5DF2\u5B58\u5728\uFF1A${state.graphExists ? "\u662F" : "\u5426"}
697
+ - \u5DF2\u914D\u7F6E\u5B89\u88C5\u547D\u4EE4\uFF1A${options.installCommand ?? "\u65E0"}
698
+
699
+ IDE LLM \u5B89\u88C5\u6D41\u7A0B\uFF1A
700
+
701
+ 1. \u5148\u68C0\u6D4B shell\u3001\u64CD\u4F5C\u7CFB\u7EDF\u3001\u5305\u7BA1\u7406\u5668\u548C PATH\u3002\u8D77\u6B65\u9636\u6BB5\u53EA\u8FD0\u884C\u53EA\u8BFB\u68C0\u6D4B\u547D\u4EE4\u3002
702
+ 2. \u8FD0\u884C \`gitnexus --version\` \u6216\u4E0A\u65B9\u663E\u793A\u7684\u53EF\u6267\u884C\u6587\u4EF6\u3002\u5982\u679C\u6210\u529F\uFF0C\u8DF3\u8FC7\u5B89\u88C5\u5E76\u8FDB\u5165\u9A8C\u8BC1\u3002
703
+ 3. \u5982\u679C GitNexus \u7F3A\u5931\u4E14\u5DF2\u914D\u7F6E \`FET_GITNEXUS_INSTALL_COMMAND\`\uFF0C\u5148\u5411\u7528\u6237\u89E3\u91CA\u8BE5\u547D\u4EE4\uFF0C\u518D\u7B49\u5F85\u7528\u6237\u6279\u51C6\u540E\u6267\u884C\u3002
704
+ 4. \u5982\u679C\u6CA1\u6709\u914D\u7F6E\u5B89\u88C5\u547D\u4EE4\uFF0C\u67E5\u627E GitNexus \u5B98\u65B9\u5B89\u88C5\u8BF4\u660E\uFF0C\u6216\u8BE2\u95EE\u7528\u6237\u5E0C\u671B\u4F7F\u7528\u7684\u5B89\u88C5\u65B9\u5F0F\u3002\u4E0D\u8981\u81C6\u9020\u5B89\u88C5\u547D\u4EE4\u3002
705
+ 5. \u4EFB\u4F55\u4F1A\u4E0B\u8F7D\u8F6F\u4EF6\u3001\u5168\u5C40\u5B89\u88C5\u3001\u4FEE\u6539 PATH\u3001\u5199\u5165\u7528\u6237\u76EE\u5F55\u6216\u4FEE\u6539 IDE/MCP \u914D\u7F6E\u7684\u547D\u4EE4\uFF0C\u6267\u884C\u524D\u90FD\u8981\u5C55\u793A\u5B8C\u6574\u547D\u4EE4\u5E76\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u3002
706
+ 6. \u5B89\u88C5\u540E\u8FD0\u884C \`gitnexus --version\` \u9A8C\u8BC1\u3002
707
+ 7. \u5982\u679C\u7528\u6237\u9700\u8981 IDE/MCP \u96C6\u6210\uFF0C\u5148\u8BF4\u660E \`gitnexus setup\` \u53EF\u80FD\u4FEE\u6539\u7684\u5185\u5BB9\uFF0C\u83B7\u5F97\u786E\u8BA4\u540E\u518D\u8FD0\u884C\u3002
708
+ 8. \u56DE\u5230\u672C\u9879\u76EE\u8FD0\u884C \`fet graph init\`\uFF0C\u751F\u6210\u7B2C\u4E00\u4EFD\u4EE3\u7801\u56FE\u3002
709
+ 9. \u8FD0\u884C \`fet graph handoff\`\uFF0C\u8BA9\u540E\u7EED IDE AI \u5728\u5927\u8303\u56F4\u626B\u63CF\u524D\u4F18\u5148\u4F7F\u7528\u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\u3002
710
+
711
+ \u7EA6\u675F\uFF1A
712
+
713
+ - GitNexus \u4E0D\u53EF\u7528\u65F6\uFF0C\u4E0D\u8981\u963B\u585E FET/OpenSpec \u547D\u4EE4\u3002
714
+ - \u5B89\u88C5\u8FC7\u7A0B\u4E2D\u4E0D\u8981\u751F\u6210\u6216\u4FEE\u6539\u4E1A\u52A1\u4EE3\u7801\u3002
715
+ - \u4E0D\u8981\u9759\u9ED8\u5B89\u88C5\u8F6F\u4EF6\uFF0C\u4E5F\u4E0D\u8981\u9759\u9ED8\u4FEE\u6539\u5168\u5C40\u6216\u7528\u6237\u7EA7\u914D\u7F6E\u3002
716
+ - \u5982\u679C\u5B89\u88C5\u5931\u8D25\uFF0C\u6C47\u603B\u5931\u8D25\u547D\u4EE4\u3001stderr \u548C\u4E0B\u4E00\u6B65\u4EBA\u5DE5\u5904\u7406\u5EFA\u8BAE\u3002
717
+ `;
718
+ }
719
+ function renderGraphUsageHandoff(state, language) {
720
+ if (language === "en") {
721
+ return `<!-- FET:MANAGED
722
+ schemaVersion: 1
652
723
  generator: graph-handoff
653
724
  FET:END -->
654
725
 
@@ -676,6 +747,37 @@ When producing OpenSpec artifacts:
676
747
  - Use graph context to make proposal, design, specs, and tasks more precise.
677
748
  - Avoid large repository scans when the graph already narrows the relevant area.
678
749
  - Keep all generated artifacts in the normal OpenSpec change directory.
750
+ `;
751
+ }
752
+ return `<!-- FET:MANAGED
753
+ schemaVersion: 1
754
+ generator: graph-handoff
755
+ FET:END -->
756
+
757
+ # FET \u4EE3\u7801\u56FE\u4EA4\u63A5\u8BF4\u660E
758
+
759
+ \u5728\u5927\u8303\u56F4\u626B\u63CF\u4ED3\u5E93\u524D\uFF0C\u4F18\u5148\u628A GitNexus \u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\u4F5C\u4E3A\u53EF\u9009\u7684\u7B2C\u4E00\u8F6E\u7EBF\u7D22\u3002
760
+
761
+ \u5F53\u524D\u72B6\u6001\uFF1A
762
+
763
+ - \u5DF2\u5B89\u88C5\uFF1A${state.installed ? "\u662F" : "\u5426"}
764
+ - \u56FE\u8DEF\u5F84\uFF1A${state.graphPath ?? ".gitnexus"}
765
+ - \u56FE\u5DF2\u5B58\u5728\uFF1A${state.graphExists ? "\u662F" : "\u5426"}
766
+ - \u6700\u540E\u7D22\u5F15\u65F6\u95F4\uFF1A${state.lastIndexedAt ?? "unknown"}
767
+ - \u6700\u540E\u72B6\u6001\uFF1A${state.lastStatus ?? "unknown"}
768
+
769
+ \u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\u53EF\u7528\u65F6\uFF1A
770
+
771
+ 1. \u7528\u4EE3\u7801\u56FE\u8BC6\u522B\u53EF\u80FD\u76F8\u5173\u7684\u6A21\u5757\u3001\u4F9D\u8D56\u548C\u63D2\u5165\u70B9\u3002
772
+ 2. \u53EA\u8BFB\u53D6\u9700\u8981\u786E\u8BA4\u884C\u4E3A\u7684\u5177\u4F53\u6E90\u7801\u6587\u4EF6\u3002
773
+ 3. \u5F53\u4EE3\u7801\u56FE\u63A8\u65AD\u4E0E OpenSpec \u4EA7\u7269\u6216 AGENTS.md \u51B2\u7A81\u65F6\uFF0C\u4F18\u5148\u76F8\u4FE1 OpenSpec \u4EA7\u7269\u548C AGENTS.md\u3002
774
+ 4. \u5982\u679C\u4EE3\u7801\u56FE\u7F3A\u5931\u3001\u8FC7\u671F\u6216\u4E0D\u5B8C\u6574\uFF0C\u56DE\u9000\u5230\u666E\u901A\u4ED3\u5E93\u68C0\u67E5\u3002
775
+
776
+ \u751F\u6210 OpenSpec \u4EA7\u7269\u65F6\uFF1A
777
+
778
+ - \u7528\u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\u8BA9 proposal\u3001design\u3001specs \u548C tasks \u66F4\u7CBE\u786E\u3002
779
+ - \u5F53\u4EE3\u7801\u56FE\u5DF2\u7ECF\u7F29\u5C0F\u76F8\u5173\u8303\u56F4\u65F6\uFF0C\u907F\u514D\u5927\u8303\u56F4\u4ED3\u5E93\u626B\u63CF\u3002
780
+ - \u6240\u6709\u751F\u6210\u4EA7\u7269\u4ECD\u5199\u5165\u6B63\u5E38\u7684 OpenSpec change \u76EE\u5F55\u3002
679
781
  `;
680
782
  }
681
783
  function firstLine(value) {
@@ -975,8 +1077,8 @@ function renderFetConfig(scan, language = "zh-CN") {
975
1077
  var KARPATHY_SKILLS_SOURCE = "https://github.com/forrestchang/andrej-karpathy-skills";
976
1078
  var BEGIN = "<!-- FET:BEGIN ANDREJ-KARPATHY-SKILLS -->";
977
1079
  var END = "<!-- FET:END ANDREJ-KARPATHY-SKILLS -->";
978
- function mergeKarpathyClaudeMd(existing) {
979
- const block = renderManagedBlock(renderKarpathyClaudeGuidelines());
1080
+ function mergeKarpathyClaudeMd(existing, language = "zh-CN") {
1081
+ const block = renderManagedBlock(renderKarpathyClaudeGuidelines(language));
980
1082
  if (!existing || !existing.trim()) {
981
1083
  return `${block}
982
1084
  `;
@@ -1021,10 +1123,10 @@ function renderManagedBlock(content) {
1021
1123
  ${content}
1022
1124
  ${END}`;
1023
1125
  }
1024
- function renderKarpathyClaudeGuidelines() {
1025
- return `# Andrej Karpathy Inspired Coding Guidelines
1126
+ function renderKarpathyClaudeGuidelines(language) {
1127
+ return `# ${language === "en" ? "Andrej Karpathy Inspired Coding Guidelines" : "\u53D7 Andrej Karpathy \u542F\u53D1\u7684\u7F16\u7801\u6307\u5357"}
1026
1128
 
1027
- ${renderKarpathyGuidelinesBody()}`;
1129
+ ${renderKarpathyGuidelinesBody(language)}`;
1028
1130
  }
1029
1131
  function renderKarpathyGuidelinesBody(language = "zh-CN") {
1030
1132
  if (language === "en") {
@@ -1225,7 +1327,7 @@ async function updateContextFiles(ctx) {
1225
1327
  }
1226
1328
  await atomicWrite(agentsPath, replaceManagedRegion(existingAgents, renderAgentsMd(scan, ctx.language)));
1227
1329
  await atomicWrite(configPath, await mergeFetConfig(configPath, renderFetConfig(scan, ctx.language)));
1228
- await atomicWrite(claudePath, mergeKarpathyClaudeMd(existingClaude));
1330
+ await atomicWrite(claudePath, mergeKarpathyClaudeMd(existingClaude, ctx.language));
1229
1331
  await atomicWrite(karpathyHandoffPath, renderKarpathyFetHandoff(ctx.language));
1230
1332
  if (!existingKarpathyCursor || existingKarpathyCursor.includes("FET:MANAGED")) {
1231
1333
  await atomicWrite(karpathyCursorPath, renderKarpathyCursorRule(ctx.language));
@@ -2013,10 +2115,10 @@ function getModelPolicyMode(env = process.env) {
2013
2115
  if (value === "off" || env.FET_SKIP_MODEL_POLICY === "1") {
2014
2116
  return "off";
2015
2117
  }
2016
- if (value === "confirm") {
2017
- return "confirm";
2118
+ if (value === "warn") {
2119
+ return "warn";
2018
2120
  }
2019
- return "warn";
2121
+ return "confirm";
2020
2122
  }
2021
2123
  function getCommandModelPolicyMismatch(command, env = process.env) {
2022
2124
  if (getModelPolicyMode(env) === "off") {
@@ -2060,14 +2162,14 @@ function formatModelPolicyMismatch(mismatch, language = "zh-CN") {
2060
2162
  function renderIdeModelPolicy(command, language = "zh-CN") {
2061
2163
  if (language === "en") {
2062
2164
  if (command === "apply") {
2063
- return "Model policy: this command is recommended to run with a high-capability/high-cost model such as GPT-5.5, GLM-5.1, GLM-5, Claude Opus, or Claude Sonnet. Treat this as advisory: do not interrupt the workflow solely to ask about switching models. Run the FET command unless the user explicitly asks to pause for a model switch, and report any FET model warning in the summary.";
2165
+ return "Model policy: this command is recommended to run with a high-capability/high-cost model such as GPT-5.5, GLM-5.1, GLM-5, Claude Opus, or Claude Sonnet. If the current IDE model is lower-cost, tell the user and ask whether to stop for a model switch or continue anyway. Continue only after the user chooses.";
2064
2166
  }
2065
- return "Model policy: this command is recommended to run with a low-cost model. If the current IDE model is GPT-5.5, GLM-5.1, GLM-5, Claude Opus, Claude Sonnet, or another high-cost model, treat it as an advisory warning: do not interrupt the workflow solely to ask about switching models. Run the FET command unless the user explicitly asks to pause for a model switch, and report any FET model warning in the summary.";
2167
+ return "Model policy: this command is recommended to run with a low-cost model. If the current IDE model is GPT-5.5, GLM-5.1, GLM-5, Claude Opus, Claude Sonnet, or another high-cost model, tell the user and ask whether to stop for a model switch or continue anyway. Continue only after the user chooses.";
2066
2168
  }
2067
2169
  if (command === "apply") {
2068
- return "\u6A21\u578B\u7B56\u7565\uFF1A\u8BE5\u547D\u4EE4\u5EFA\u8BAE\u4F7F\u7528\u9AD8\u80FD\u529B/\u9AD8\u6210\u672C\u6A21\u578B\u8FD0\u884C\uFF0C\u4F8B\u5982 GPT-5.5\u3001GLM-5.1\u3001GLM-5\u3001Claude Opus \u6216 Claude Sonnet\u3002\u6B64\u63D0\u793A\u4EC5\u4F5C\u4E3A\u5EFA\u8BAE\uFF0C\u4E0D\u8981\u4EC5\u56E0\u6A21\u578B\u7B56\u7565\u800C\u6253\u65AD\u6D41\u7A0B\u8BE2\u95EE\u662F\u5426\u5207\u6362\u6A21\u578B\uFF1B\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5148\u5207\u6362\u6A21\u578B\uFF0C\u5426\u5219\u7EE7\u7EED\u8FD0\u884C FET \u547D\u4EE4\uFF0C\u5E76\u5728\u603B\u7ED3\u4E2D\u8BF4\u660E FET \u8F93\u51FA\u7684\u6A21\u578B\u63D0\u9192\u3002";
2170
+ return "\u6A21\u578B\u7B56\u7565\uFF1A\u8BE5\u547D\u4EE4\u5EFA\u8BAE\u4F7F\u7528\u9AD8\u80FD\u529B/\u9AD8\u6210\u672C\u6A21\u578B\u8FD0\u884C\uFF0C\u4F8B\u5982 GPT-5.5\u3001GLM-5.1\u3001GLM-5\u3001Claude Opus \u6216 Claude Sonnet\u3002\u82E5\u5F53\u524D IDE \u6A21\u578B\u80FD\u529B\u8F83\u4F4E\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u5E76\u8BE2\u95EE\u662F\u505C\u6B62\u540E\u5207\u6362\u6A21\u578B\uFF0C\u8FD8\u662F\u7EE7\u7EED\u6267\u884C\u5F53\u524D\u547D\u4EE4\uFF1B\u53EA\u6709\u5728\u7528\u6237\u9009\u62E9\u540E\u624D\u7EE7\u7EED\u3002";
2069
2171
  }
2070
- return "\u6A21\u578B\u7B56\u7565\uFF1A\u8BE5\u547D\u4EE4\u5EFA\u8BAE\u4F7F\u7528\u4F4E\u6210\u672C\u6A21\u578B\u8FD0\u884C\u3002\u82E5\u5F53\u524D IDE \u6A21\u578B\u662F GPT-5.5\u3001GLM-5.1\u3001GLM-5\u3001Claude Opus\u3001Claude Sonnet \u6216\u5176\u4ED6\u9AD8\u6210\u672C\u6A21\u578B\uFF0C\u6B64\u63D0\u793A\u4EC5\u4F5C\u4E3A\u5EFA\u8BAE\uFF1B\u4E0D\u8981\u4EC5\u56E0\u6A21\u578B\u7B56\u7565\u800C\u6253\u65AD\u6D41\u7A0B\u8BE2\u95EE\u662F\u5426\u5207\u6362\u6A21\u578B\u3002\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u5148\u5207\u6362\u6A21\u578B\uFF0C\u5426\u5219\u7EE7\u7EED\u8FD0\u884C FET \u547D\u4EE4\uFF0C\u5E76\u5728\u603B\u7ED3\u4E2D\u8BF4\u660E FET \u8F93\u51FA\u7684\u6A21\u578B\u63D0\u9192\u3002";
2172
+ return "\u6A21\u578B\u7B56\u7565\uFF1A\u8BE5\u547D\u4EE4\u5EFA\u8BAE\u4F7F\u7528\u4F4E\u6210\u672C\u6A21\u578B\u8FD0\u884C\u3002\u82E5\u5F53\u524D IDE \u6A21\u578B\u662F GPT-5.5\u3001GLM-5.1\u3001GLM-5\u3001Claude Opus\u3001Claude Sonnet \u6216\u5176\u4ED6\u9AD8\u6210\u672C\u6A21\u578B\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u5E76\u8BE2\u95EE\u662F\u505C\u6B62\u540E\u5207\u6362\u6A21\u578B\uFF0C\u8FD8\u662F\u7EE7\u7EED\u6267\u884C\u5F53\u524D\u547D\u4EE4\uFF1B\u53EA\u6709\u5728\u7528\u6237\u9009\u62E9\u540E\u624D\u7EE7\u7EED\u3002";
2071
2173
  }
2072
2174
 
2073
2175
  // src/cli/context.ts
@@ -2107,18 +2209,9 @@ function renderFetAdapterUsage(command, args = "[...args]") {
2107
2209
 
2108
2210
  // src/adapters/codex/templates.ts
2109
2211
  function codexGuideFile(language = DEFAULT_LANGUAGE) {
2110
- return {
2111
- path: ".codex/fet/context.md",
2112
- content: `<!-- FET:MANAGED
2113
- schemaVersion: 1
2114
- fetVersion: ${FET_VERSION}
2115
- generator: codex-adapter
2116
- adapterVersion: 1
2117
- FET:END -->
2118
-
2119
- # FET For Codex
2212
+ const body = language === "en" ? `# FET For Codex
2120
2213
 
2121
- ## \u8BED\u8A00
2214
+ ## Language
2122
2215
 
2123
2216
  ${languageInstruction(language)}
2124
2217
 
@@ -2134,7 +2227,35 @@ If GitNexus code graph context is available in the IDE or MCP tools, prefer it b
2134
2227
  Use the terminal command \`fet <command>\` as the source of truth for workflow transitions. These files are Codex-readable guidance; they do not register native slash commands.
2135
2228
 
2136
2229
  Command guides live in .codex/fet/commands/.
2137
- `
2230
+ ` : `# Codex \u7684 FET \u4F7F\u7528\u6307\u5357
2231
+
2232
+ ## \u8BED\u8A00
2233
+
2234
+ ${languageInstruction(language)}
2235
+
2236
+ \u5728 Codex \u4E2D\u6267\u884C FET \u6216 OpenSpec \u5DE5\u4F5C\u524D\uFF0C\u5148\u9605\u8BFB\uFF1A
2237
+
2238
+ - AGENTS.md
2239
+ - openspec/config.yaml
2240
+ - .codex/fet/karpathy-guidelines.md
2241
+ - \u5982\u679C\u5DF2\u9009\u62E9 change\uFF0C\u9605\u8BFB openspec/changes/<change-id>/ \u4E0B\u7684\u5F53\u524D\u4EA7\u7269
2242
+
2243
+ \u5982\u679C IDE \u6216 MCP \u5DE5\u5177\u4E2D\u53EF\u7528 GitNexus \u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\uFF0C\u5148\u7528\u5B83\u7F29\u5C0F\u4ED3\u5E93\u626B\u63CF\u8303\u56F4\uFF1B\u7528\u56FE\u8BC6\u522B\u76F8\u5173\u6A21\u5757\u3001\u4F9D\u8D56\u548C\u63D2\u5165\u70B9\uFF0C\u518D\u53EA\u8BFB\u53D6\u9700\u8981\u786E\u8BA4\u884C\u4E3A\u7684\u5177\u4F53\u6E90\u7801\u6587\u4EF6\u3002GitNexus \u4E0D\u53EF\u7528\u65F6\uFF0C\u6309\u666E\u901A FET/OpenSpec \u5DE5\u4F5C\u6D41\u7EE7\u7EED\u3002
2244
+
2245
+ \u5DE5\u4F5C\u6D41\u6D41\u8F6C\u4EE5\u7EC8\u7AEF\u547D\u4EE4 \`fet <command>\` \u4E3A\u51C6\u3002\u8FD9\u4E9B\u6587\u4EF6\u662F\u7ED9 Codex \u9605\u8BFB\u7684\u6307\u5BFC\uFF0C\u4E0D\u6CE8\u518C\u539F\u751F slash command\u3002
2246
+
2247
+ \u547D\u4EE4\u6307\u5357\u4F4D\u4E8E .codex/fet/commands/\u3002
2248
+ `;
2249
+ return {
2250
+ path: ".codex/fet/context.md",
2251
+ content: `<!-- FET:MANAGED
2252
+ schemaVersion: 1
2253
+ fetVersion: ${FET_VERSION}
2254
+ generator: codex-adapter
2255
+ adapterVersion: 1
2256
+ FET:END -->
2257
+
2258
+ ${body}`
2138
2259
  };
2139
2260
  }
2140
2261
  function codexCommandFiles(language = DEFAULT_LANGUAGE) {
@@ -2162,7 +2283,7 @@ generator: codex-adapter
2162
2283
  adapterVersion: 1
2163
2284
  FET:END -->
2164
2285
 
2165
- # Andrej Karpathy Inspired Coding Guidelines
2286
+ # ${language === "en" ? "Andrej Karpathy Inspired Coding Guidelines" : "\u53D7 Andrej Karpathy \u542F\u53D1\u7684\u7F16\u7801\u6307\u5357"}
2166
2287
 
2167
2288
  ${renderKarpathyGuidelinesBody(language)}
2168
2289
  `
@@ -2216,6 +2337,34 @@ After the command completes, report the important next steps from the FET output
2216
2337
  function renderCommandZh(command) {
2217
2338
  const usage = renderFetAdapterUsage(command, command === "fill-context" ? "" : command === "passthrough" ? "<openspec-command> [...args]" : "");
2218
2339
  const title = commandTitleZh(command);
2340
+ if (command === "graph-setup") {
2341
+ return `<!-- FET:MANAGED
2342
+ schemaVersion: 1
2343
+ fetVersion: ${FET_VERSION}
2344
+ generator: codex-adapter
2345
+ adapterVersion: 1
2346
+ command: ${usage}
2347
+ FET:END -->
2348
+
2349
+ # ${usage}
2350
+
2351
+ ${renderIdeModelPolicy(command, "zh-CN")}
2352
+
2353
+ ${languageInstruction("zh-CN")}
2354
+
2355
+ \u7528\u4E8E\u6307\u5BFC\u5F53\u524D IDE LLM \u5728\u7528\u6237\u786E\u8BA4\u4E0B\u5B89\u88C5 GitNexus\u3002
2356
+
2357
+ \u5148\u8FD0\u884C\uFF1A
2358
+
2359
+ \`\`\`sh
2360
+ ${usage}
2361
+ \`\`\`
2362
+
2363
+ \u7136\u540E\u9605\u8BFB .fet/graph-setup.md\uFF0C\u5E76\u4EE5\u5B83\u4F5C\u4E3A\u5B89\u88C5\u4EFB\u52A1\u4E66\u3002\u53EA\u8BFB\u68C0\u6D4B\u547D\u4EE4\u53EF\u4EE5\u76F4\u63A5\u8FD0\u884C\uFF1B\u4EFB\u4F55\u4F1A\u4E0B\u8F7D\u8F6F\u4EF6\u3001\u5168\u5C40\u5B89\u88C5\u3001\u4FEE\u6539 PATH\u3001\u5199\u5165\u7528\u6237\u7EA7\u6587\u4EF6\u6216\u4FEE\u6539 IDE/MCP \u914D\u7F6E\u7684\u547D\u4EE4\uFF0C\u6267\u884C\u524D\u90FD\u8981\u5C55\u793A\u5B8C\u6574\u547D\u4EE4\u5E76\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u3002
2364
+
2365
+ \u5B89\u88C5\u540E\u7528 \`gitnexus --version\` \u9A8C\u8BC1\u3002\u5408\u9002\u65F6\u7EE7\u7EED\u8FD0\u884C \`fet graph init\` \u548C \`fet graph handoff\`\u3002\u5982\u679C\u5B89\u88C5\u5931\u8D25\uFF0C\u62A5\u544A\u5931\u8D25\u547D\u4EE4\u3001stderr \u548C\u4E0B\u4E00\u6B65\u4EBA\u5DE5\u5904\u7406\u5EFA\u8BAE\u3002
2366
+ `;
2367
+ }
2219
2368
  return `<!-- FET:MANAGED
2220
2369
  schemaVersion: 1
2221
2370
  fetVersion: ${FET_VERSION}
@@ -2279,6 +2428,34 @@ This preserves the FET entry point while allowing access to unmanaged or newly a
2279
2428
  }
2280
2429
  function renderGraphCommand(command, language) {
2281
2430
  const usage = renderFetAdapterUsage(command, "");
2431
+ if (command === "graph-setup") {
2432
+ return `<!-- FET:MANAGED
2433
+ schemaVersion: 1
2434
+ fetVersion: ${FET_VERSION}
2435
+ generator: codex-adapter
2436
+ adapterVersion: 1
2437
+ command: ${usage}
2438
+ FET:END -->
2439
+
2440
+ # ${usage}
2441
+
2442
+ ${renderIdeModelPolicy(command, language)}
2443
+
2444
+ ${languageInstruction(language)}
2445
+
2446
+ Use this command to guide IDE-assisted GitNexus installation with user approval.
2447
+
2448
+ Run:
2449
+
2450
+ \`\`\`sh
2451
+ ${usage}
2452
+ \`\`\`
2453
+
2454
+ Then read .fet/graph-setup.md and follow it as the source of truth. You may run read-only detection commands directly. Before downloading software, installing globally, changing PATH, writing user-level files, or modifying IDE/MCP configuration, show the exact command and wait for user approval.
2455
+
2456
+ After installation, verify \`gitnexus --version\`. If appropriate, continue with \`fet graph init\` and \`fet graph handoff\`. If installation fails, report the failing command, stderr, and next manual step.
2457
+ `;
2458
+ }
2282
2459
  const subcommand = command.slice("graph-".length);
2283
2460
  return `<!-- FET:MANAGED
2284
2461
  schemaVersion: 1
@@ -2351,6 +2528,9 @@ function renderSlashPrompt(command, language) {
2351
2528
  if (command === "passthrough") {
2352
2529
  return renderPassthroughSlashPrompt(language);
2353
2530
  }
2531
+ if (command === "graph-setup") {
2532
+ return renderGraphSetupSlashPrompt(language);
2533
+ }
2354
2534
  const usage = renderFetAdapterUsage(command);
2355
2535
  const isGraph = command.startsWith("graph-");
2356
2536
  const shellCommand = isGraph ? `${renderFetAdapterUsage(command, "")} $ARGUMENTS` : `fet ${command} $ARGUMENTS`;
@@ -2385,6 +2565,9 @@ After it completes, summarize the important FET output and next steps.
2385
2565
  `;
2386
2566
  }
2387
2567
  function renderSlashPromptZh(command) {
2568
+ if (command === "graph-setup") {
2569
+ return renderGraphSetupSlashPrompt("zh-CN");
2570
+ }
2388
2571
  const usage = renderFetAdapterUsage(command, command === "fill-context" ? "" : command === "passthrough" ? "<openspec-command> [...args]" : "[...args]");
2389
2572
  const argumentHint = command === "passthrough" ? "openspec-command [...args]" : void 0;
2390
2573
  const argumentHintLine = argumentHint ? `argument-hint: ${argumentHint}
@@ -2778,6 +2961,62 @@ Guardrails:
2778
2961
  language
2779
2962
  );
2780
2963
  }
2964
+ function renderGraphSetupSlashPrompt(language) {
2965
+ if (language === "en") {
2966
+ return renderManagedSlashPrompt(
2967
+ "fet graph setup",
2968
+ "Guide IDE-assisted GitNexus installation with user approval",
2969
+ `Guide optional GitNexus installation for this project.
2970
+
2971
+ Steps:
2972
+
2973
+ 1. Run:
2974
+ \`\`\`sh
2975
+ fet graph setup
2976
+ \`\`\`
2977
+ 2. Read .fet/graph-setup.md and follow it as the source of truth.
2978
+ 3. Run read-only detection commands as needed, such as checking the shell, PATH, package managers, and \`gitnexus --version\`.
2979
+ 4. If GitNexus is missing, use the configured \`FET_GITNEXUS_INSTALL_COMMAND\` when present; otherwise find the official GitNexus installation instructions or ask the user for the preferred method.
2980
+ 5. Before any command that downloads software, installs globally, changes PATH, writes user-level files, or modifies IDE/MCP settings, show the exact command and wait for user approval.
2981
+ 6. Verify installation with \`gitnexus --version\`.
2982
+ 7. If the user wants IDE/MCP integration, explain \`gitnexus setup\` and run it only after approval.
2983
+ 8. Run \`fet graph init\` and then \`fet graph handoff\` when GitNexus is available.
2984
+
2985
+ Guardrails:
2986
+ - GitNexus is optional; do not block FET/OpenSpec workflows if installation fails.
2987
+ - Do not modify application code during setup.
2988
+ - Report the failing command, stderr, and next manual step if blocked.`,
2989
+ void 0,
2990
+ language
2991
+ );
2992
+ }
2993
+ return renderManagedSlashPrompt(
2994
+ "fet graph setup",
2995
+ "\u6307\u5BFC IDE LLM \u5728\u7528\u6237\u786E\u8BA4\u4E0B\u5B89\u88C5 GitNexus",
2996
+ `\u4E3A\u5F53\u524D\u9879\u76EE\u5F15\u5BFC\u53EF\u9009\u7684 GitNexus \u5B89\u88C5\u3002
2997
+
2998
+ \u6B65\u9AA4\uFF1A
2999
+
3000
+ 1. \u8FD0\u884C\uFF1A
3001
+ \`\`\`sh
3002
+ fet graph setup
3003
+ \`\`\`
3004
+ 2. \u9605\u8BFB .fet/graph-setup.md\uFF0C\u5E76\u4EE5\u5B83\u4F5C\u4E3A\u5B89\u88C5\u4EFB\u52A1\u4E66\u3002
3005
+ 3. \u6309\u9700\u8FD0\u884C\u53EA\u8BFB\u68C0\u6D4B\u547D\u4EE4\uFF0C\u4F8B\u5982\u68C0\u67E5 shell\u3001PATH\u3001\u5305\u7BA1\u7406\u5668\u548C \`gitnexus --version\`\u3002
3006
+ 4. \u5982\u679C GitNexus \u7F3A\u5931\uFF0C\u4F18\u5148\u4F7F\u7528\u5DF2\u914D\u7F6E\u7684 \`FET_GITNEXUS_INSTALL_COMMAND\`\uFF1B\u6CA1\u6709\u914D\u7F6E\u65F6\uFF0C\u67E5\u627E GitNexus \u5B98\u65B9\u5B89\u88C5\u8BF4\u660E\uFF0C\u6216\u8BE2\u95EE\u7528\u6237\u5E0C\u671B\u4F7F\u7528\u7684\u5B89\u88C5\u65B9\u5F0F\u3002
3007
+ 5. \u4EFB\u4F55\u4F1A\u4E0B\u8F7D\u8F6F\u4EF6\u3001\u5168\u5C40\u5B89\u88C5\u3001\u4FEE\u6539 PATH\u3001\u5199\u5165\u7528\u6237\u7EA7\u6587\u4EF6\u6216\u4FEE\u6539 IDE/MCP \u8BBE\u7F6E\u7684\u547D\u4EE4\uFF0C\u6267\u884C\u524D\u90FD\u8981\u5C55\u793A\u5B8C\u6574\u547D\u4EE4\u5E76\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u3002
3008
+ 6. \u7528 \`gitnexus --version\` \u9A8C\u8BC1\u5B89\u88C5\u3002
3009
+ 7. \u5982\u679C\u7528\u6237\u9700\u8981 IDE/MCP \u96C6\u6210\uFF0C\u5148\u8BF4\u660E \`gitnexus setup\`\uFF0C\u83B7\u5F97\u786E\u8BA4\u540E\u518D\u8FD0\u884C\u3002
3010
+ 8. GitNexus \u53EF\u7528\u540E\u8FD0\u884C \`fet graph init\`\uFF0C\u518D\u8FD0\u884C \`fet graph handoff\`\u3002
3011
+
3012
+ \u7EA6\u675F\uFF1A
3013
+ - GitNexus \u662F\u53EF\u9009\u80FD\u529B\uFF1B\u5B89\u88C5\u5931\u8D25\u65F6\u4E0D\u8981\u963B\u585E FET/OpenSpec \u4E3B\u6D41\u7A0B\u3002
3014
+ - \u5B89\u88C5\u8FC7\u7A0B\u4E2D\u4E0D\u8981\u4FEE\u6539\u4E1A\u52A1\u4EE3\u7801\u3002
3015
+ - \u5982\u679C\u53D7\u963B\uFF0C\u62A5\u544A\u5931\u8D25\u547D\u4EE4\u3001stderr \u548C\u4E0B\u4E00\u6B65\u4EBA\u5DE5\u5904\u7406\u5EFA\u8BAE\u3002`,
3016
+ void 0,
3017
+ language
3018
+ );
3019
+ }
2781
3020
  function renderExploreSlashPrompt(language) {
2782
3021
  return renderManagedSlashPrompt(
2783
3022
  "fet explore [...args]",
@@ -2897,6 +3136,7 @@ function renderManagedSlashPrompt(command, description, body, argumentHint, lang
2897
3136
  const policyCommand = command.split(/\s+/)[1] ?? command;
2898
3137
  const argumentHintLine = argumentHint ? `argument-hint: ${argumentHint}
2899
3138
  ` : "";
3139
+ const graphContextInstruction = language === "en" ? "If GitNexus graph context is available, consult it before broad source scans and use it to narrow the files you read. If it is unavailable, continue normally." : "\u5982\u679C GitNexus \u4EE3\u7801\u56FE\u4E0A\u4E0B\u6587\u53EF\u7528\uFF0C\u5148\u7528\u5B83\u7F29\u5C0F\u6E90\u7801\u626B\u63CF\u8303\u56F4\uFF1B\u4E0D\u53EF\u7528\u65F6\u6309\u666E\u901A\u6D41\u7A0B\u7EE7\u7EED\u3002";
2900
3140
  return `<!-- FET:MANAGED
2901
3141
  schemaVersion: 1
2902
3142
  fetVersion: ${FET_VERSION}
@@ -2913,7 +3153,7 @@ ${renderIdeModelPolicy(policyCommand, language)}
2913
3153
 
2914
3154
  ${languageInstruction(language)}
2915
3155
 
2916
- If GitNexus graph context is available, consult it before broad source scans and use it to narrow the files you read. If it is unavailable, continue normally.
3156
+ ${graphContextInstruction}
2917
3157
 
2918
3158
  ${body}
2919
3159
  `;
@@ -3088,6 +3328,36 @@ ${languageInstruction(language)}
3088
3328
  - openspec/config.yaml
3089
3329
 
3090
3330
  \u68C0\u67E5 README\u3001package scripts\u3001\u8DEF\u7531\u3001\u6D4B\u8BD5\u3001\u6E90\u7801\u7ED3\u6784\u548C\u73B0\u6709\u7EA6\u5B9A\u540E\uFF0C\u628A AGENTS.md \u4E2D\u6BCF\u4E2A \`[NEEDS LLM INPUT]\` \u6216 \`[NEED LLM INPUT]\` \u5360\u4F4D\u7B26\u66FF\u6362\u4E3A\u5177\u4F53\u3001\u7B80\u6D01\u3001\u9879\u76EE\u76F8\u5173\u7684\u5185\u5BB9\u3002\u4FDD\u7559 FET \u6258\u7BA1\u6807\u8BB0\uFF0C\u4E0D\u8981\u4FEE\u6539\u4E1A\u52A1\u4EE3\u7801\u3002
3331
+ `;
3332
+ }
3333
+ if (command === "graph-setup") {
3334
+ return `<!-- FET:MANAGED
3335
+ schemaVersion: 1
3336
+ fetVersion: ${FET_VERSION}
3337
+ generator: cursor-adapter
3338
+ adapterVersion: 1
3339
+ command: fet graph setup
3340
+ FET:END -->
3341
+
3342
+ ---
3343
+ name: fet-graph-setup
3344
+ description: ${language === "en" ? "Guide IDE-assisted GitNexus installation with user approval" : "\u6307\u5BFC IDE LLM \u5728\u7528\u6237\u786E\u8BA4\u4E0B\u5B89\u88C5 GitNexus"}
3345
+ disable-model-invocation: false
3346
+ ---
3347
+
3348
+ ${renderIdeModelPolicy(command, language)}
3349
+
3350
+ ${languageInstruction(language)}
3351
+
3352
+ ${language === "en" ? `Run \`fet graph setup\`, then read .fet/graph-setup.md and follow it as an installation playbook.
3353
+
3354
+ You may run read-only detection commands without extra confirmation. Before any command that downloads software, installs globally, changes PATH, writes user-level config, or modifies IDE/MCP settings, show the exact command and wait for user approval.
3355
+
3356
+ After installation, verify with \`gitnexus --version\`, then run \`fet graph init\` and \`fet graph handoff\` when appropriate. If installation fails, summarize the failing command and next manual step.` : `\u5148\u8FD0\u884C \`fet graph setup\`\uFF0C\u518D\u9605\u8BFB .fet/graph-setup.md\uFF0C\u5E76\u628A\u5B83\u4F5C\u4E3A\u5B89\u88C5\u4EFB\u52A1\u4E66\u6267\u884C\u3002
3357
+
3358
+ \u53EA\u8BFB\u68C0\u6D4B\u547D\u4EE4\u53EF\u4EE5\u76F4\u63A5\u8FD0\u884C\u3002\u4EFB\u4F55\u4F1A\u4E0B\u8F7D\u8F6F\u4EF6\u3001\u5168\u5C40\u5B89\u88C5\u3001\u4FEE\u6539 PATH\u3001\u5199\u5165\u7528\u6237\u7EA7\u914D\u7F6E\u6216\u4FEE\u6539 IDE/MCP \u8BBE\u7F6E\u7684\u547D\u4EE4\uFF0C\u6267\u884C\u524D\u90FD\u8981\u5C55\u793A\u5B8C\u6574\u547D\u4EE4\u5E76\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u3002
3359
+
3360
+ \u5B89\u88C5\u540E\u7528 \`gitnexus --version\` \u9A8C\u8BC1\uFF1B\u5408\u9002\u65F6\u7EE7\u7EED\u8FD0\u884C \`fet graph init\` \u548C \`fet graph handoff\`\u3002\u5982\u679C\u5B89\u88C5\u5931\u8D25\uFF0C\u6C47\u603B\u5931\u8D25\u547D\u4EE4\u548C\u4E0B\u4E00\u6B65\u4EBA\u5DE5\u5904\u7406\u5EFA\u8BAE\u3002`}
3091
3361
  `;
3092
3362
  }
3093
3363
  return `<!-- FET:MANAGED
@@ -3805,7 +4075,7 @@ function renderModelPolicyActionHint(policyMode, language) {
3805
4075
  if (policyMode === "confirm") {
3806
4076
  return language === "en" ? "Choose whether to continue this command or stop and switch models." : "\u8BF7\u9009\u62E9\u7EE7\u7EED\u6267\u884C\u672C\u547D\u4EE4\uFF0C\u6216\u505C\u6B62\u540E\u624B\u52A8\u5207\u6362\u6A21\u578B\u3002";
3807
4077
  }
3808
- return language === "en" ? "This is advisory; the command will continue. Set FET_MODEL_POLICY=confirm if you want an explicit stop/continue prompt." : "\u8BE5\u63D0\u9192\u4EC5\u4F5C\u4E3A\u5EFA\u8BAE\uFF0C\u547D\u4EE4\u4F1A\u7EE7\u7EED\u6267\u884C\u3002\u5982\u9700\u663E\u5F0F\u9009\u62E9\u505C\u6B62\u6216\u7EE7\u7EED\uFF0C\u53EF\u8BBE\u7F6E FET_MODEL_POLICY=confirm\u3002";
4078
+ return language === "en" ? "This is advisory because FET_MODEL_POLICY=warn; the command will continue." : "\u5F53\u524D\u8BBE\u7F6E FET_MODEL_POLICY=warn\uFF0C\u8BE5\u63D0\u9192\u4EC5\u4F5C\u4E3A\u5EFA\u8BAE\uFF0C\u547D\u4EE4\u4F1A\u7EE7\u7EED\u6267\u884C\u3002";
3809
4079
  }
3810
4080
  async function warnIfContextPlaceholdersRemain(ctx) {
3811
4081
  if (["init", "update-context", "fill-context", "doctor"].includes(ctx.command)) {