@nick848/fet 1.1.8 → 1.1.9

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
@@ -9,7 +9,7 @@ import { createInterface as createInterface3 } from "readline/promises";
9
9
  import { Command } from "commander";
10
10
 
11
11
  // src/commands/doctor.ts
12
- import { readFile as readFile4, stat as stat3 } from "fs/promises";
12
+ import { stat as stat3 } from "fs/promises";
13
13
  import { join as join6 } from "path";
14
14
 
15
15
  // src/context-placeholders.ts
@@ -268,7 +268,10 @@ async function doctorCommand(ctx, options = {}) {
268
268
  checks.push(await checkState(ctx));
269
269
  checks.push(await checkFile("agents", join6(ctx.projectRoot, "AGENTS.md"), "AGENTS.md \u7F3A\u5931", "fet update-context"));
270
270
  checks.push(await checkFile("config", join6(ctx.projectRoot, "openspec", "config.yaml"), "openspec/config.yaml \u7F3A\u5931", "fet init"));
271
- checks.push(await checkPlaceholders(ctx));
271
+ const placeholders = await checkPlaceholders(ctx);
272
+ if (placeholders) {
273
+ checks.push(placeholders);
274
+ }
272
275
  checks.push(await checkGitNexus(ctx));
273
276
  for (const adapter of ctx.toolAdapters) {
274
277
  checks.push(...await adapter.doctor(ctx.projectRoot));
@@ -333,27 +336,21 @@ async function checkFile(id, path, missing, suggestedCommand) {
333
336
  return await exists(path) ? { id, status: "pass", message: `${id} \u5B58\u5728` } : { id, status: "warn", message: missing, suggestedCommand };
334
337
  }
335
338
  async function checkPlaceholders(ctx) {
336
- try {
337
- await readFile4(join6(ctx.projectRoot, "AGENTS.md"), "utf8");
338
- const count2 = await countAgentsLlmPlaceholders(ctx.projectRoot);
339
- return count2 ? {
340
- id: "context-placeholders",
341
- status: "warn",
342
- message: ctx.language === "en" ? `AGENTS.md has ${count2} LLM placeholder(s)` : `AGENTS.md \u4ECD\u6709 ${count2} \u4E2A LLM \u5360\u4F4D\u7B26`,
343
- suggestedCommand: "fet fill-context"
344
- } : {
345
- id: "context-placeholders",
346
- status: "pass",
347
- message: ctx.language === "en" ? "AGENTS.md placeholders resolved" : "AGENTS.md \u5360\u4F4D\u7B26\u5DF2\u5904\u7406"
348
- };
349
- } catch {
350
- return {
351
- id: "context-placeholders",
352
- status: "warn",
353
- message: ctx.language === "en" ? "AGENTS.md missing" : "AGENTS.md \u7F3A\u5931",
354
- suggestedCommand: "fet update-context"
355
- };
339
+ const agentsPath = join6(ctx.projectRoot, "AGENTS.md");
340
+ if (!await exists(agentsPath)) {
341
+ return null;
356
342
  }
343
+ const count2 = await countAgentsLlmPlaceholders(ctx.projectRoot);
344
+ return count2 ? {
345
+ id: "context-placeholders",
346
+ status: "warn",
347
+ message: ctx.language === "en" ? `AGENTS.md has ${count2} LLM placeholder(s)` : `AGENTS.md \u4ECD\u6709 ${count2} \u4E2A LLM \u5360\u4F4D\u7B26`,
348
+ suggestedCommand: "fet fill-context"
349
+ } : {
350
+ id: "context-placeholders",
351
+ status: "pass",
352
+ message: ctx.language === "en" ? "AGENTS.md placeholders resolved" : "AGENTS.md \u5360\u4F4D\u7B26\u5DF2\u5904\u7406"
353
+ };
357
354
  }
358
355
  async function exists(path) {
359
356
  try {
@@ -369,20 +366,20 @@ import { mkdir as mkdir3 } from "fs/promises";
369
366
  import { dirname as dirname4, join as join10 } from "path";
370
367
 
371
368
  // src/agents-miniprogram.ts
372
- import { readFile as readFile7 } from "fs/promises";
369
+ import { readFile as readFile6 } from "fs/promises";
373
370
  import { join as join9 } from "path";
374
371
 
375
372
  // src/scanner/miniprogram.ts
376
- import { readdir, readFile as readFile6, stat as stat5 } from "fs/promises";
373
+ import { readdir, readFile as readFile5, stat as stat5 } from "fs/promises";
377
374
  import { join as join8, relative } from "path";
378
375
 
379
376
  // src/scanner/package.ts
380
- import { readFile as readFile5, stat as stat4 } from "fs/promises";
377
+ import { readFile as readFile4, stat as stat4 } from "fs/promises";
381
378
  import { join as join7 } from "path";
382
379
  import { parse } from "yaml";
383
380
  async function readPackageJson(projectRoot) {
384
381
  try {
385
- return JSON.parse(await readFile5(join7(projectRoot, "package.json"), "utf8"));
382
+ return JSON.parse(await readFile4(join7(projectRoot, "package.json"), "utf8"));
386
383
  } catch {
387
384
  return null;
388
385
  }
@@ -463,7 +460,7 @@ async function detectWorkspaces(projectRoot, pkg) {
463
460
  return packageWorkspaces;
464
461
  }
465
462
  try {
466
- const workspace = parse(await readFile5(join7(projectRoot, "pnpm-workspace.yaml"), "utf8"));
463
+ const workspace = parse(await readFile4(join7(projectRoot, "pnpm-workspace.yaml"), "utf8"));
467
464
  return (workspace?.packages ?? []).map((path) => ({
468
465
  name: path,
469
466
  path,
@@ -604,7 +601,7 @@ async function resolveAppJsonPath(projectRoot, platform) {
604
601
  const candidates = [];
605
602
  if (platform.id === "wechat") {
606
603
  try {
607
- const config = JSON.parse(await readFile6(join8(projectRoot, "project.config.json"), "utf8"));
604
+ const config = JSON.parse(await readFile5(join8(projectRoot, "project.config.json"), "utf8"));
608
605
  if (config.miniprogramRoot) {
609
606
  candidates.push(join8(projectRoot, config.miniprogramRoot, "app.json"));
610
607
  }
@@ -628,7 +625,7 @@ async function resolveAppJsonPath(projectRoot, platform) {
628
625
  }
629
626
  async function readAppJson(path) {
630
627
  try {
631
- return JSON.parse(await readFile6(path, "utf8"));
628
+ return JSON.parse(await readFile5(path, "utf8"));
632
629
  } catch {
633
630
  return null;
634
631
  }
@@ -991,7 +988,7 @@ async function applyMiniprogramAgentsContext(projectRoot, language) {
991
988
  const detection = await detectMiniprogramProject(projectRoot);
992
989
  let existing;
993
990
  try {
994
- existing = await readFile7(agentsPath, "utf8");
991
+ existing = await readFile6(agentsPath, "utf8");
995
992
  } catch {
996
993
  return {
997
994
  applied: false,
@@ -1116,7 +1113,7 @@ import { mkdir as mkdir5 } from "fs/promises";
1116
1113
  import { dirname as dirname6, join as join12 } from "path";
1117
1114
 
1118
1115
  // src/graph-context.ts
1119
- import { mkdir as mkdir4, readdir as readdir2, readFile as readFile8 } from "fs/promises";
1116
+ import { mkdir as mkdir4, readdir as readdir2, readFile as readFile7 } from "fs/promises";
1120
1117
  import { dirname as dirname5, join as join11 } from "path";
1121
1118
  var MAX_SOURCE_CONTEXT = 8e3;
1122
1119
  var MAX_GRAPH_OUTPUT = 2e4;
@@ -1362,7 +1359,7 @@ async function listSpecFiles(specsRoot) {
1362
1359
  }
1363
1360
  async function readOptional(path) {
1364
1361
  try {
1365
- return await readFile8(path, "utf8");
1362
+ return await readFile7(path, "utf8");
1366
1363
  } catch {
1367
1364
  return null;
1368
1365
  }
@@ -1768,19 +1765,19 @@ import { stat as stat6 } from "fs/promises";
1768
1765
  import { join as join15 } from "path";
1769
1766
 
1770
1767
  // src/commands/update-context.ts
1771
- import { readFile as readFile10 } from "fs/promises";
1768
+ import { readFile as readFile9 } from "fs/promises";
1772
1769
  import { createInterface } from "readline/promises";
1773
1770
  import { join as join14 } from "path";
1774
1771
 
1775
1772
  // src/config/yaml.ts
1776
- import { readFile as readFile9 } from "fs/promises";
1773
+ import { readFile as readFile8 } from "fs/promises";
1777
1774
  import { parseDocument } from "yaml";
1778
1775
  async function mergeFetConfig(configPath, renderedFetYaml) {
1779
1776
  const fetDoc = parseDocument(renderedFetYaml);
1780
1777
  const nextFet = fetDoc.get("fet", true);
1781
1778
  let existing = "";
1782
1779
  try {
1783
- existing = await readFile9(configPath, "utf8");
1780
+ existing = await readFile8(configPath, "utf8");
1784
1781
  } catch {
1785
1782
  return renderedFetYaml;
1786
1783
  }
@@ -2824,7 +2821,7 @@ async function confirmInitCanReplaceUnmanagedAgents(ctx) {
2824
2821
  }
2825
2822
  async function readOptional2(path) {
2826
2823
  try {
2827
- return await readFile10(path, "utf8");
2824
+ return await readFile9(path, "utf8");
2828
2825
  } catch {
2829
2826
  return null;
2830
2827
  }
@@ -2892,11 +2889,11 @@ async function exists4(path) {
2892
2889
  }
2893
2890
 
2894
2891
  // src/commands/proxy.ts
2895
- import { readFile as readFile15 } from "fs/promises";
2892
+ import { readFile as readFile14 } from "fs/promises";
2896
2893
  import { join as join19 } from "path";
2897
2894
 
2898
2895
  // src/figma-guard.ts
2899
- import { readdir as readdir3, readFile as readFile11, stat as stat7 } from "fs/promises";
2896
+ import { readdir as readdir3, readFile as readFile10, stat as stat7 } from "fs/promises";
2900
2897
  import { join as join16, relative as relative2 } from "path";
2901
2898
  import { parseDocument as parseDocument2 } from "yaml";
2902
2899
  var DEFAULT_CONFIG = {
@@ -2906,7 +2903,7 @@ var DEFAULT_CONFIG = {
2906
2903
  };
2907
2904
  async function loadFigmaGuardConfig(projectRoot) {
2908
2905
  try {
2909
- const raw = await readFile11(join16(projectRoot, "openspec", "config.yaml"), "utf8");
2906
+ const raw = await readFile10(join16(projectRoot, "openspec", "config.yaml"), "utf8");
2910
2907
  const doc = parseDocument2(raw);
2911
2908
  const fetNode = doc.get("fet", true);
2912
2909
  const node = fetNode?.get?.("figmaGuard");
@@ -3042,7 +3039,7 @@ async function walk(dir, files) {
3042
3039
  async function readOptional3(path) {
3043
3040
  try {
3044
3041
  await stat7(path);
3045
- return await readFile11(path, "utf8");
3042
+ return await readFile10(path, "utf8");
3046
3043
  } catch {
3047
3044
  return null;
3048
3045
  }
@@ -3050,7 +3047,7 @@ async function readOptional3(path) {
3050
3047
 
3051
3048
  // src/ui-display-contract.ts
3052
3049
  import { existsSync as existsSync2 } from "fs";
3053
- import { readdir as readdir4, readFile as readFile12, stat as stat8 } from "fs/promises";
3050
+ import { readdir as readdir4, readFile as readFile11, stat as stat8 } from "fs/promises";
3054
3051
  import { join as join17, relative as relative3 } from "path";
3055
3052
  import { parse as parse3, parseDocument as parseDocument3 } from "yaml";
3056
3053
  var DEFAULT_CONFIG2 = {
@@ -3062,7 +3059,7 @@ var BACKTICK_PATH_PATTERN = /`([^`]+\.(?:ya?ml|json))`/gi;
3062
3059
  var OPENAPI_BARE_PATTERN = /\b(openapi\.ya?ml|swagger\.ya?ml|swagger\.json)\b/gi;
3063
3060
  async function loadUiDisplayContractConfig(projectRoot) {
3064
3061
  try {
3065
- const raw = await readFile12(join17(projectRoot, "openspec", "config.yaml"), "utf8");
3062
+ const raw = await readFile11(join17(projectRoot, "openspec", "config.yaml"), "utf8");
3066
3063
  const doc = parseDocument3(raw);
3067
3064
  const fetNode = doc.get("fet", true);
3068
3065
  const node = fetNode?.get?.("uiDisplayContract");
@@ -3336,7 +3333,7 @@ async function walk2(dir, files) {
3336
3333
  async function readOptional4(path) {
3337
3334
  try {
3338
3335
  await stat8(path);
3339
- return await readFile12(path, "utf8");
3336
+ return await readFile11(path, "utf8");
3340
3337
  } catch {
3341
3338
  return null;
3342
3339
  }
@@ -3369,7 +3366,7 @@ async function git(cwd, args) {
3369
3366
  }
3370
3367
 
3371
3368
  // src/state/store.ts
3372
- import { mkdir as mkdir6, readFile as readFile13 } from "fs/promises";
3369
+ import { mkdir as mkdir6, readFile as readFile12 } from "fs/promises";
3373
3370
  import { join as join18 } from "path";
3374
3371
 
3375
3372
  // src/language.ts
@@ -3488,7 +3485,7 @@ var StateStore = class {
3488
3485
  project;
3489
3486
  async readGlobal() {
3490
3487
  try {
3491
- const value = JSON.parse(await readFile13(this.globalPath(), "utf8"));
3488
+ const value = JSON.parse(await readFile12(this.globalPath(), "utf8"));
3492
3489
  assertGlobalState(value);
3493
3490
  return value;
3494
3491
  } catch (error) {
@@ -3509,7 +3506,7 @@ var StateStore = class {
3509
3506
  }
3510
3507
  async readChange(changeId) {
3511
3508
  try {
3512
- const value = JSON.parse(await readFile13(this.changePath(changeId), "utf8"));
3509
+ const value = JSON.parse(await readFile12(this.changePath(changeId), "utf8"));
3513
3510
  assertChangeState(value);
3514
3511
  return value;
3515
3512
  } catch (error) {
@@ -3540,11 +3537,11 @@ function isNotFound(error) {
3540
3537
  }
3541
3538
 
3542
3539
  // src/state/tasks.ts
3543
- import { readFile as readFile14 } from "fs/promises";
3540
+ import { readFile as readFile13 } from "fs/promises";
3544
3541
  async function readCompletedTaskIds(tasksPath) {
3545
3542
  let content;
3546
3543
  try {
3547
- content = await readFile14(tasksPath, "utf8");
3544
+ content = await readFile13(tasksPath, "utf8");
3548
3545
  } catch {
3549
3546
  return [];
3550
3547
  }
@@ -4157,7 +4154,7 @@ function summarizeMarkdown(content) {
4157
4154
  }
4158
4155
  async function readOptional5(path) {
4159
4156
  try {
4160
- return await readFile15(path, "utf8");
4157
+ return await readFile14(path, "utf8");
4161
4158
  } catch {
4162
4159
  return null;
4163
4160
  }
@@ -4513,8 +4510,11 @@ async function updateCommand(ctx) {
4513
4510
 
4514
4511
  // src/commands/verify.ts
4515
4512
  import { createHash } from "crypto";
4516
- import { mkdir as mkdir7, readFile as readFile16, stat as stat9 } from "fs/promises";
4513
+ import { mkdir as mkdir7, readFile as readFile15, stat as stat9 } from "fs/promises";
4517
4514
  import { join as join20 } from "path";
4515
+ function msg(language, zh, en) {
4516
+ return language === "en" ? en : zh;
4517
+ }
4518
4518
  async function verifyCommand(ctx, options) {
4519
4519
  if (options.auto) {
4520
4520
  const scan = await ctx.scanner.scan(ctx.projectRoot, {});
@@ -4600,7 +4600,7 @@ async function markDone(ctx, changeId) {
4600
4600
  await assertChangeExists(ctx, changeId);
4601
4601
  const declaredAt = (/* @__PURE__ */ new Date()).toISOString();
4602
4602
  const instructionsPath = join20(ctx.projectRoot, "openspec", "changes", changeId, ".fet", "verify-instructions.md");
4603
- const instructions = await readInstructions(instructionsPath, changeId);
4603
+ const instructions = await readInstructions(ctx, instructionsPath, changeId);
4604
4604
  const instructionsGeneratedAt = readFrontMatterValue(instructions, "generatedAt") ?? declaredAt;
4605
4605
  const state = await ctx.stateStore.getOrCreateChange(changeId, "verify");
4606
4606
  state.currentPhase = "verify";
@@ -4626,21 +4626,25 @@ async function assertChangeExists(ctx, changeId) {
4626
4626
  if (!inspection.exists) {
4627
4627
  throw new FetError({
4628
4628
  code: "INVALID_ARGUMENTS" /* InvalidArguments */,
4629
- message: "\u6307\u5B9A\u7684 change \u4E0D\u5B58\u5728",
4629
+ message: msg(ctx.language, "\u6307\u5B9A\u7684 change \u4E0D\u5B58\u5728", "The specified change does not exist"),
4630
4630
  details: { changeId },
4631
- suggestedCommand: "fet verify --change <change-id>"
4631
+ suggestedCommand: `fet verify --change ${changeId}`
4632
4632
  });
4633
4633
  }
4634
4634
  }
4635
- async function readInstructions(path, changeId) {
4635
+ async function readInstructions(ctx, path, changeId) {
4636
4636
  try {
4637
4637
  await stat9(path);
4638
- const content = await readFile16(path, "utf8");
4638
+ const content = await readFile15(path, "utf8");
4639
4639
  const fileChangeId = readFrontMatterValue(content, "changeId");
4640
4640
  if (fileChangeId !== changeId) {
4641
4641
  throw new FetError({
4642
4642
  code: "STATE_CORRUPTED" /* StateCorrupted */,
4643
- message: "\u9A8C\u8BC1\u6307\u4EE4\u6587\u4EF6\u4E0E\u5F53\u524D change \u4E0D\u5339\u914D",
4643
+ message: msg(
4644
+ ctx.language,
4645
+ "\u9A8C\u8BC1\u6307\u4EE4\u6587\u4EF6\u4E0E\u5F53\u524D change \u4E0D\u5339\u914D",
4646
+ "Verify instructions do not match the current change"
4647
+ ),
4644
4648
  details: { expected: changeId, actual: fileChangeId },
4645
4649
  suggestedCommand: `fet verify --change ${changeId}`
4646
4650
  });
@@ -4652,7 +4656,7 @@ async function readInstructions(path, changeId) {
4652
4656
  }
4653
4657
  throw new FetError({
4654
4658
  code: "STATE_CORRUPTED" /* StateCorrupted */,
4655
- message: "\u9A8C\u8BC1\u6307\u4EE4\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BFB\u53D6",
4659
+ message: msg(ctx.language, "\u9A8C\u8BC1\u6307\u4EE4\u6587\u4EF6\u4E0D\u5B58\u5728\u6216\u65E0\u6CD5\u8BFB\u53D6", "Verify instructions file is missing or unreadable"),
4656
4660
  details: { path },
4657
4661
  suggestedCommand: `fet verify --change ${changeId}`
4658
4662
  });
@@ -4679,7 +4683,7 @@ async function resolveChangeId(ctx) {
4679
4683
  }
4680
4684
  throw new FetError({
4681
4685
  code: "INVALID_ARGUMENTS" /* InvalidArguments */,
4682
- message: "\u65E0\u6CD5\u786E\u5B9A\u8981\u9A8C\u8BC1\u7684 change",
4686
+ message: msg(ctx.language, "\u65E0\u6CD5\u786E\u5B9A\u8981\u9A8C\u8BC1\u7684 change", "Cannot determine which change to verify"),
4683
4687
  details: { openChangeIds: inspection.changes },
4684
4688
  suggestedCommand: "fet verify --change <change-id>"
4685
4689
  });
@@ -4773,7 +4777,7 @@ function renderIdeModelPolicy(command, language = "zh-CN") {
4773
4777
  import { resolve } from "path";
4774
4778
 
4775
4779
  // src/adapters/codex/index.ts
4776
- import { mkdir as mkdir8, readFile as readFile17, stat as stat10 } from "fs/promises";
4780
+ import { mkdir as mkdir8, readFile as readFile16, stat as stat10 } from "fs/promises";
4777
4781
  import { homedir } from "os";
4778
4782
  import { dirname as dirname8, join as join21 } from "path";
4779
4783
 
@@ -5941,7 +5945,7 @@ function resolveCodexHome() {
5941
5945
  }
5942
5946
  async function readExisting(path) {
5943
5947
  try {
5944
- return await readFile17(path, "utf8");
5948
+ return await readFile16(path, "utf8");
5945
5949
  } catch {
5946
5950
  return null;
5947
5951
  }
@@ -5956,7 +5960,7 @@ async function exists5(path) {
5956
5960
  }
5957
5961
 
5958
5962
  // src/adapters/cursor/index.ts
5959
- import { mkdir as mkdir9, readFile as readFile18, stat as stat11 } from "fs/promises";
5963
+ import { mkdir as mkdir9, readFile as readFile17, stat as stat11 } from "fs/promises";
5960
5964
  import { dirname as dirname9, join as join22 } from "path";
5961
5965
 
5962
5966
  // src/adapters/cursor/templates.ts
@@ -6271,7 +6275,7 @@ var CursorAdapter = class {
6271
6275
  };
6272
6276
  async function readExisting2(path) {
6273
6277
  try {
6274
- return await readFile18(path, "utf8");
6278
+ return await readFile17(path, "utf8");
6275
6279
  } catch {
6276
6280
  return null;
6277
6281
  }
@@ -6713,7 +6717,7 @@ async function createCommandContext(command, options) {
6713
6717
  import { createInterface as createInterface2 } from "readline/promises";
6714
6718
 
6715
6719
  // src/update/check.ts
6716
- import { mkdir as mkdir10, readFile as readFile19, writeFile } from "fs/promises";
6720
+ import { mkdir as mkdir10, readFile as readFile18, writeFile } from "fs/promises";
6717
6721
  import { homedir as homedir2 } from "os";
6718
6722
  import { dirname as dirname10, join as join25 } from "path";
6719
6723
  var DEFAULT_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
@@ -6792,7 +6796,7 @@ function cachePath() {
6792
6796
  }
6793
6797
  async function readUpdateCheckCache() {
6794
6798
  try {
6795
- const raw = await readFile19(cachePath(), "utf8");
6799
+ const raw = await readFile18(cachePath(), "utf8");
6796
6800
  const parsed = JSON.parse(raw);
6797
6801
  if (typeof parsed.latestVersion !== "string" || typeof parsed.checkedAt !== "string") {
6798
6802
  return null;