pi-usereq 0.12.0 → 0.32.0

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.
@@ -12,6 +12,7 @@ import { spawnSync } from "node:child_process";
12
12
  import {
13
13
  createStaticCheckLanguageConfig,
14
14
  DEFAULT_DOCS_DIR,
15
+ getDefaultConfig,
15
16
  getProjectConfigPath,
16
17
  type UseReqConfig,
17
18
  } from "../src/core/config.js";
@@ -21,6 +22,7 @@ import {
21
22
  createTempDir,
22
23
  getFixtureFiles,
23
24
  initFixtureRepo,
25
+ readGlobalConfigJson,
24
26
  readProjectConfigJson,
25
27
  runNodeCli,
26
28
  runPythonCli,
@@ -115,11 +117,11 @@ function getFixtureTagFilter(filePath: string): string {
115
117
  }
116
118
 
117
119
  /**
118
- * @brief Returns the persisted per-language static-check config for one language.
119
- * @details Reads the raw project config JSON so tests can assert entry order, duplicate suppression, enable-flag persistence, and metadata preservation exactly as written. Runtime is O(n) in config file size. Side effects are limited to filesystem reads.
120
+ * @brief Returns the persisted local static-check config for one language.
121
+ * @details Reads the raw local project config JSON so tests can assert enable-flag persistence and local-scope shape exactly as written. Runtime is O(n) in config file size. Side effects are limited to filesystem reads.
120
122
  * @param[in] projectBase {string} Fixture project root.
121
123
  * @param[in] language {string} Canonical language key.
122
- * @return {Record<string, unknown> | undefined} Persisted language config object when present.
124
+ * @return {Record<string, unknown> | undefined} Persisted local language config object when present.
123
125
  */
124
126
  function getStaticCheckLanguageConfig(projectBase: string, language: string): Record<string, unknown> | undefined {
125
127
  const payload = readProjectConfigJson(projectBase);
@@ -128,14 +130,17 @@ function getStaticCheckLanguageConfig(projectBase: string, language: string): Re
128
130
  }
129
131
 
130
132
  /**
131
- * @brief Returns the persisted static-check entries for one language.
132
- * @details Reads the raw project config JSON and extracts the `checkers` array so tests can assert entry order and duplicate suppression exactly as written. Runtime is O(n) in config file size. Side effects are limited to filesystem reads.
133
- * @param[in] projectBase {string} Fixture project root.
133
+ * @brief Returns the persisted global static-check entries for one language.
134
+ * @details Reads the raw global config JSON and extracts the `checkers` array so tests can assert entry order and duplicate suppression exactly as written. Runtime is O(n) in config file size. Side effects are limited to filesystem reads.
135
+ * @param[in] projectBase {string} Fixture project root retained for stable call-site shape.
134
136
  * @param[in] language {string} Canonical language key.
135
- * @return {Array<Record<string, unknown>>} Persisted checker-entry array or an empty array.
137
+ * @return {Array<Record<string, unknown>>} Persisted global checker-entry array or an empty array.
136
138
  */
137
139
  function getStaticCheckEntries(projectBase: string, language: string): Array<Record<string, unknown>> {
138
- const languageConfig = getStaticCheckLanguageConfig(projectBase, language);
140
+ void projectBase;
141
+ const payload = readGlobalConfigJson();
142
+ const staticCheck = (payload["static-check"] ?? {}) as Record<string, Record<string, unknown>>;
143
+ const languageConfig = staticCheck[language];
139
144
  return Array.isArray(languageConfig?.checkers)
140
145
  ? languageConfig.checkers as Array<Record<string, unknown>>
141
146
  : [];
@@ -594,6 +599,7 @@ const TARGET_CASES: TargetParityCase[] = [
594
599
  fs.mkdirSync(path.join(projectBase, "src"), { recursive: true });
595
600
  fs.mkdirSync(path.join(projectBase, "tests"), { recursive: true });
596
601
  fs.mkdirSync(path.join(projectBase, ...DEFAULT_DOCS_DIR.split("/")), { recursive: true });
602
+ const originalGlobalConfig = structuredClone(readGlobalConfigJson());
597
603
  const result = runNodeCli(
598
604
  ["--base", projectBase, "--enable-static-check", "C=Command,nonexistent_tool_xyz_12345"],
599
605
  projectBase,
@@ -601,6 +607,7 @@ const TARGET_CASES: TargetParityCase[] = [
601
607
  assert.equal(result.status, 1);
602
608
  assert.match(result.stderr, /not an executable program/);
603
609
  assert.ok(!fs.existsSync(getProjectConfigPath(projectBase)));
610
+ assert.deepEqual(readGlobalConfigJson(), originalGlobalConfig);
604
611
 
605
612
  const removedModule = runNodeCli(
606
613
  ["--base", projectBase, "--enable-static-check", "Python=Ruff"],
@@ -609,6 +616,7 @@ const TARGET_CASES: TargetParityCase[] = [
609
616
  assert.equal(removedModule.status, 1);
610
617
  assert.match(removedModule.stderr, /unknown module/i);
611
618
  assert.ok(!fs.existsSync(getProjectConfigPath(projectBase)));
619
+ assert.deepEqual(readGlobalConfigJson(), originalGlobalConfig);
612
620
  },
613
621
  },
614
622
  {
@@ -629,13 +637,18 @@ const TARGET_CASES: TargetParityCase[] = [
629
637
  projectBase,
630
638
  );
631
639
  assert.equal(persisted.status, 0, persisted.stderr);
640
+ const defaultConfig = getDefaultConfig(projectBase);
632
641
  assert.equal(getStaticCheckLanguageConfig(projectBase, "Python")?.enabled, "enable");
633
642
  assert.equal(getStaticCheckLanguageConfig(projectBase, "C")?.enabled, "enable");
634
643
  assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [
644
+ ...defaultConfig["static-check"].Python.checkers,
635
645
  { module: "Command", cmd: "git", params: ["--version"] },
636
646
  { module: "Command", cmd: "git", params: ["--help"] },
637
647
  ]);
638
- assert.deepEqual(getStaticCheckEntries(projectBase, "C"), [{ module: "Command", cmd: "git", params: ["--version"] }]);
648
+ assert.deepEqual(getStaticCheckEntries(projectBase, "C"), [
649
+ ...defaultConfig["static-check"].C.checkers,
650
+ { module: "Command", cmd: "git", params: ["--version"] },
651
+ ]);
639
652
  },
640
653
  },
641
654
  {
@@ -658,10 +671,15 @@ const TARGET_CASES: TargetParityCase[] = [
658
671
  projectBase,
659
672
  );
660
673
  assert.equal(result.status, 0, result.stderr);
674
+ const defaultConfig = getDefaultConfig(projectBase);
661
675
  assert.equal(getStaticCheckLanguageConfig(projectBase, "Python")?.enabled, "enable");
662
676
  assert.equal(getStaticCheckLanguageConfig(projectBase, "C")?.enabled, "enable");
663
- assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [{ module: "Command", cmd: "git", params: ["--version"] }]);
677
+ assert.deepEqual(getStaticCheckEntries(projectBase, "Python"), [
678
+ ...defaultConfig["static-check"].Python.checkers,
679
+ { module: "Command", cmd: "git", params: ["--version"] },
680
+ ]);
664
681
  assert.deepEqual(getStaticCheckEntries(projectBase, "C"), [
682
+ ...defaultConfig["static-check"].C.checkers,
665
683
  { module: "Command", cmd: "git", params: ["--version"] },
666
684
  { module: "Command", cmd: "git", params: ["--help"] },
667
685
  ]);
@@ -12,22 +12,21 @@ import {
12
12
  type OfflineContractSnapshot,
13
13
  } from "../scripts/lib/extension-debug-harness.js";
14
14
  import { buildParityReport, type SdkContractSnapshot } from "../scripts/lib/sdk-smoke.js";
15
- import { getProjectConfigPath } from "../src/core/config.js";
15
+ import { loadConfig } from "../src/core/config.js";
16
16
  import { PI_USEREQ_STATUS_HOOK_NAMES } from "../src/core/extension-status.js";
17
- import { initFixtureRepo } from "./helpers.js";
17
+ import { initFixtureRepo, saveFixtureConfigs } from "./helpers.js";
18
18
 
19
19
  /**
20
20
  * @brief Persists a targeted enabled-tool list into a fixture project config.
21
- * @details Loads `.pi-usereq.json`, replaces the `enabled-tools` array with the supplied values, and writes the updated JSON back to disk with a trailing newline. Runtime is O(n) in config size. Side effects include filesystem reads and file overwrite.
21
+ * @details Loads the effective split config, replaces the global `enabled-tools` array with the supplied values, and rewrites the local/global plus oracle mirror files so offline harness tests observe the same runtime state. Runtime is O(n) in config size. Side effects include filesystem reads and file overwrite.
22
22
  * @param[in] projectBase {string} Fixture project root.
23
23
  * @param[in] enabledTools {string[]} Enabled-tool names to persist.
24
24
  * @return {void} No return value.
25
25
  */
26
26
  function writeEnabledTools(projectBase: string, enabledTools: string[]): void {
27
- const configPath = getProjectConfigPath(projectBase);
28
- const config = JSON.parse(fs.readFileSync(configPath, "utf8")) as Record<string, unknown>;
27
+ const config = loadConfig(projectBase);
29
28
  config["enabled-tools"] = enabledTools;
30
- fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
29
+ saveFixtureConfigs(projectBase, config);
31
30
  }
32
31
 
33
32
  /**
@@ -257,10 +256,9 @@ test("replaySessionStart captures active tools, statuses, and cwd semantics", as
257
256
  test("replayCommand captures prompt command payloads", async () => {
258
257
  const { projectBase } = initFixtureRepo();
259
258
  try {
260
- const configPath = getProjectConfigPath(projectBase);
261
- const config = JSON.parse(fs.readFileSync(configPath, "utf8")) as Record<string, unknown>;
259
+ const config = loadConfig(projectBase);
262
260
  config.GIT_WORKTREE_ENABLED = "disable";
263
- fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf8");
261
+ saveFixtureConfigs(projectBase, config);
264
262
  assert.equal(spawnSync("git", ["add", ".pi-usereq.json", ".req/config.json"], {
265
263
  cwd: projectBase,
266
264
  encoding: "utf8",