pi-usereq 0.12.0 → 0.13.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.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/pi-usereq/docs/REFERENCES.md +509 -335
- package/pi-usereq/docs/REQUIREMENTS.md +53 -40
- package/pi-usereq/docs/WORKFLOW.md +67 -36
- package/src/core/config.ts +541 -180
- package/src/core/extension-status.ts +2 -2
- package/src/core/path-context.ts +19 -4
- package/src/index.ts +82 -35
- package/tests/attended-results-scenarios.ts +10 -4
- package/tests/cli-command-option-parity.test.ts +28 -10
- package/tests/debug-extension-harness.test.ts +7 -9
- package/tests/extension-registration.test.ts +170 -118
- package/tests/helpers.ts +29 -6
|
@@ -689,7 +689,7 @@ export function setPiUsereqStatusConfig(
|
|
|
689
689
|
|
|
690
690
|
/**
|
|
691
691
|
* @brief Returns the active runtime sound level tracked by the status controller.
|
|
692
|
-
* @details Exposes the in-memory runtime sound state so shortcut handlers and prompt-end notification dispatch can stay decoupled from the persisted boot value stored in
|
|
692
|
+
* @details Exposes the in-memory runtime sound state so shortcut handlers and prompt-end notification dispatch can stay decoupled from the persisted boot value stored in global configuration. Runtime is O(1). No external state is mutated.
|
|
693
693
|
* @param[in] controller {PiUsereqStatusController} Mutable status controller.
|
|
694
694
|
* @return {PiNotifySoundLevel} Active runtime sound level.
|
|
695
695
|
* @satisfies REQ-180, REQ-285
|
|
@@ -702,7 +702,7 @@ export function getPiUsereqRuntimeSoundLevel(
|
|
|
702
702
|
|
|
703
703
|
/**
|
|
704
704
|
* @brief Stores one new runtime sound level and refreshes the status bar.
|
|
705
|
-
* @details Mutates only the in-memory runtime sound state so shortcut-driven sound changes do not update
|
|
705
|
+
* @details Mutates only the in-memory runtime sound state so shortcut-driven sound changes do not update persisted local or global configuration, then re-renders the footer when an active extension context is available. Runtime is O(1). Side effect: mutates `controller.state.runtimeSoundLevel` and may update `ctx.ui` status.
|
|
706
706
|
* @param[in,out] controller {PiUsereqStatusController} Mutable status controller.
|
|
707
707
|
* @param[in] runtimeSoundLevel {PiNotifySoundLevel} Next active runtime sound level.
|
|
708
708
|
* @param[in] ctx {ExtensionContext | undefined} Optional active extension context.
|
package/src/core/path-context.ts
CHANGED
|
@@ -11,11 +11,17 @@ import { fileURLToPath } from "node:url";
|
|
|
11
11
|
import type { UseReqConfig } from "./config.js";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* @brief Defines the per-project configuration file name.
|
|
15
|
-
* @details The file lives directly under `base-path` and stores only persisted project configuration. Access complexity is O(1).
|
|
14
|
+
* @brief Defines the per-project local configuration file name.
|
|
15
|
+
* @details The file lives directly under `base-path` and stores only persisted project-scoped configuration. Access complexity is O(1).
|
|
16
16
|
*/
|
|
17
17
|
export const PROJECT_CONFIG_FILENAME = ".pi-usereq.json";
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @brief Defines the home-relative global configuration file path.
|
|
21
|
+
* @details The path is resolved against the current user home directory and stores persisted cross-project configuration. Access complexity is O(1).
|
|
22
|
+
*/
|
|
23
|
+
export const GLOBAL_CONFIG_RELATIVE_PATH = ".config/pi-usereq/config.json";
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* @brief Defines the bundled resources directory name under the installation path.
|
|
21
27
|
* @details The directory contains prompts, templates, and guidelines shipped with the installed extension payload. Access complexity is O(1).
|
|
@@ -155,15 +161,24 @@ export function normalizeRelativeDirContract(value: string): string {
|
|
|
155
161
|
}
|
|
156
162
|
|
|
157
163
|
/**
|
|
158
|
-
* @brief Computes the absolute project config path for one base path.
|
|
164
|
+
* @brief Computes the absolute local project config path for one base path.
|
|
159
165
|
* @details Appends `.pi-usereq.json` to the supplied base path using the canonical repository-local configuration layout. Runtime is O(1). No external state is mutated.
|
|
160
166
|
* @param[in] basePath {string} Absolute or relative base path.
|
|
161
|
-
* @return {string} Absolute config-file path.
|
|
167
|
+
* @return {string} Absolute local config-file path.
|
|
162
168
|
*/
|
|
163
169
|
export function getConfigPath(basePath: string): string {
|
|
164
170
|
return path.join(path.resolve(basePath), PROJECT_CONFIG_FILENAME);
|
|
165
171
|
}
|
|
166
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @brief Computes the absolute global config path for the current user.
|
|
175
|
+
* @details Resolves `~/.config/pi-usereq/config.json` from the current user home directory without consulting project state. Runtime is O(1). No external state is mutated.
|
|
176
|
+
* @return {string} Absolute global config-file path.
|
|
177
|
+
*/
|
|
178
|
+
export function getGlobalConfigPath(): string {
|
|
179
|
+
return path.join(os.homedir(), GLOBAL_CONFIG_RELATIVE_PATH);
|
|
180
|
+
}
|
|
181
|
+
|
|
167
182
|
/**
|
|
168
183
|
* @brief Tests whether one path is identical to or an ancestor of another path.
|
|
169
184
|
* @details Resolves both inputs, computes a relative traversal from the candidate ancestor to the candidate child, and accepts only exact matches or descendant traversals that stay within the ancestor subtree. Runtime is O(p) in path length. No external state is mutated.
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @brief Declares the extension version string.
|
|
9
9
|
* @details The value is exported for external inspection and packaging metadata alignment. Access complexity is O(1).
|
|
10
10
|
*/
|
|
11
|
-
export const VERSION = "0.
|
|
11
|
+
export const VERSION = "0.13.0";
|
|
12
12
|
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
createStaticCheckLanguageConfig,
|
|
33
33
|
getDefaultConfig,
|
|
34
34
|
getDefaultStaticCheckConfig,
|
|
35
|
+
getGlobalConfigPath,
|
|
35
36
|
getProjectConfigPath,
|
|
36
37
|
loadConfig,
|
|
37
38
|
normalizeConfigPaths,
|
|
@@ -268,12 +269,12 @@ function loadProjectConfig(cwd: string): UseReqConfig {
|
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
/**
|
|
271
|
-
* @brief Persists project configuration from the extension runtime.
|
|
272
|
-
* @details Resolves the project base, normalizes configured directory paths into project-relative form, and delegates persistence to `saveConfig` without serializing runtime-derived path metadata. Runtime is O(n) in config size. Side effects include config-file writes.
|
|
272
|
+
* @brief Persists effective project configuration from the extension runtime.
|
|
273
|
+
* @details Resolves the project base, normalizes configured local directory paths into project-relative form, and delegates split local/global persistence to `saveConfig` without serializing runtime-derived path metadata. Runtime is O(n) in config size. Side effects include config-file writes.
|
|
273
274
|
* @param[in] cwd {string} Current working directory.
|
|
274
|
-
* @param[in] config {UseReqConfig}
|
|
275
|
+
* @param[in] config {UseReqConfig} Effective configuration to persist.
|
|
275
276
|
* @return {void} No return value.
|
|
276
|
-
* @satisfies REQ-146
|
|
277
|
+
* @satisfies REQ-146, REQ-315
|
|
277
278
|
*/
|
|
278
279
|
function saveProjectConfig(cwd: string, config: UseReqConfig): void {
|
|
279
280
|
const projectBase = getProjectBase(cwd);
|
|
@@ -281,18 +282,28 @@ function saveProjectConfig(cwd: string, config: UseReqConfig): void {
|
|
|
281
282
|
}
|
|
282
283
|
|
|
283
284
|
/**
|
|
284
|
-
* @brief Formats the current
|
|
285
|
-
* @details Resolves `<base-path>/.pi-usereq.json` from the cwd-derived project base
|
|
285
|
+
* @brief Formats the current local config path for top-level menu display.
|
|
286
|
+
* @details Resolves `<base-path>/.pi-usereq.json` from the cwd-derived project base and reuses the shared runtime-path formatter so the `Show local configuration` row uses the documented `~`-relative display contract. Runtime is O(p) in path length. No external state is mutated.
|
|
286
287
|
* @param[in] cwd {string} Current working directory.
|
|
287
|
-
* @return {string} `~`-relative or absolute config
|
|
288
|
+
* @return {string} `~`-relative or absolute local config-path display value.
|
|
288
289
|
* @satisfies REQ-162
|
|
289
290
|
*/
|
|
290
|
-
function
|
|
291
|
+
function formatLocalConfigPathForMenu(cwd: string): string {
|
|
291
292
|
return formatRuntimePathForDisplay(
|
|
292
293
|
getProjectConfigPath(getProjectBase(cwd)),
|
|
293
294
|
);
|
|
294
295
|
}
|
|
295
296
|
|
|
297
|
+
/**
|
|
298
|
+
* @brief Formats the current global config path for top-level menu display.
|
|
299
|
+
* @details Resolves `~/.config/pi-usereq/config.json` through the shared runtime-path formatter so the `Show global configuration` row uses the documented `~`-relative display contract. Runtime is O(p) in path length. No external state is mutated.
|
|
300
|
+
* @return {string} `~`-relative or absolute global config-path display value.
|
|
301
|
+
* @satisfies REQ-319
|
|
302
|
+
*/
|
|
303
|
+
function formatGlobalConfigPathForMenu(): string {
|
|
304
|
+
return formatRuntimePathForDisplay(getGlobalConfigPath());
|
|
305
|
+
}
|
|
306
|
+
|
|
296
307
|
/**
|
|
297
308
|
* @brief Builds the standardized terminal rows appended to every configuration menu.
|
|
298
309
|
* @details Returns the canonical value-less `Reset defaults` row so all configuration menus and descendant selector menus share the same terminal ordering contract without rendering `Save and close`. Runtime is O(1). No external state is mutated.
|
|
@@ -409,21 +420,46 @@ async function confirmResetChanges(
|
|
|
409
420
|
}
|
|
410
421
|
|
|
411
422
|
/**
|
|
412
|
-
* @brief Writes
|
|
413
|
-
* @details Reads the
|
|
423
|
+
* @brief Writes one already-persisted config file text into the editor.
|
|
424
|
+
* @details Reads the target config file from disk after the caller has saved any pending changes and forwards the exact persisted text into the editor. Runtime is O(n) in serialized config size. Side effects include filesystem reads and editor-text mutation.
|
|
425
|
+
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
426
|
+
* @param[in] configPath {string} Absolute persisted config path.
|
|
427
|
+
* @return {void} No return value.
|
|
428
|
+
*/
|
|
429
|
+
function writePersistedConfigToEditor(
|
|
430
|
+
ctx: ExtensionCommandContext,
|
|
431
|
+
configPath: string,
|
|
432
|
+
): void {
|
|
433
|
+
ctx.ui.setEditorText(fs.readFileSync(configPath, "utf8"));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* @brief Writes the already-persisted local configuration file text into the editor.
|
|
438
|
+
* @details Reads `<base-path>/.pi-usereq.json` from disk after the caller has saved any pending local and global configuration changes, then forwards that exact persisted text into the editor. Runtime is O(n) in serialized config size. Side effects include filesystem reads and editor-text mutation.
|
|
414
439
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
415
440
|
* @param[in] cwd {string} Current working directory.
|
|
416
|
-
* @param[in] _config {UseReqConfig} Unused effective project configuration retained for stable call-site shape.
|
|
417
441
|
* @return {void} No return value.
|
|
418
442
|
* @satisfies REQ-031
|
|
419
443
|
*/
|
|
420
|
-
function
|
|
444
|
+
function writePersistedLocalConfigToEditor(
|
|
421
445
|
ctx: ExtensionCommandContext,
|
|
422
446
|
cwd: string,
|
|
423
|
-
_config: UseReqConfig,
|
|
424
447
|
): void {
|
|
425
448
|
const projectBase = getProjectBase(cwd);
|
|
426
|
-
ctx
|
|
449
|
+
writePersistedConfigToEditor(ctx, getProjectConfigPath(projectBase));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* @brief Writes the already-persisted global configuration file text into the editor.
|
|
454
|
+
* @details Reads `~/.config/pi-usereq/config.json` from disk after the caller has saved any pending local and global configuration changes, then forwards that exact persisted text into the editor. Runtime is O(n) in serialized config size. Side effects include filesystem reads and editor-text mutation.
|
|
455
|
+
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
456
|
+
* @return {void} No return value.
|
|
457
|
+
* @satisfies REQ-318
|
|
458
|
+
*/
|
|
459
|
+
function writePersistedGlobalConfigToEditor(
|
|
460
|
+
ctx: ExtensionCommandContext,
|
|
461
|
+
): void {
|
|
462
|
+
writePersistedConfigToEditor(ctx, getGlobalConfigPath());
|
|
427
463
|
}
|
|
428
464
|
|
|
429
465
|
/**
|
|
@@ -2314,7 +2350,7 @@ async function selectPiNotifySoundLevel(
|
|
|
2314
2350
|
|
|
2315
2351
|
/**
|
|
2316
2352
|
* @brief Runs the interactive notification-configuration menu.
|
|
2317
|
-
* @details Exposes command-notify, sound, and Pushover controls through the shared settings-menu renderer, delegates completed/interrupted/failed toggles to dedicated event submenus,
|
|
2353
|
+
* @details Exposes command-notify, sound, and Pushover controls through the shared settings-menu renderer, persists every notification subtree mutation into global configuration, delegates completed/interrupted/failed toggles to dedicated event submenus, preserves boot-sound edits without altering the active runtime sound level, keeps `Enable pushover` locked until both credentials are populated, decodes escaped control-sequence input for `Pushover text`, and preserves row focus across menu re-renders. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
2318
2354
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
2319
2355
|
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
2320
2356
|
* @return {Promise<boolean>} `true` when the sound-toggle shortcut changed.
|
|
@@ -2610,10 +2646,10 @@ async function configurePiNotifyMenu(
|
|
|
2610
2646
|
|
|
2611
2647
|
/**
|
|
2612
2648
|
* @brief Registers the configurable notification-sound shortcut when supported.
|
|
2613
|
-
* @details Loads the current
|
|
2649
|
+
* @details Loads the current effective config, registers one raw pi shortcut when
|
|
2614
2650
|
* the runtime exposes `registerShortcut(...)`, cycles only the active runtime
|
|
2615
|
-
* sound level on invocation, leaves
|
|
2616
|
-
* status bar, and emits one info notification. Runtime is O(1) for registration
|
|
2651
|
+
* sound level on invocation, leaves persisted local and global configuration
|
|
2652
|
+
* unchanged, refreshes the status bar, and emits one info notification. Runtime is O(1) for registration
|
|
2617
2653
|
* plus one status update per shortcut use. Side effects include shortcut
|
|
2618
2654
|
* registration and status updates.
|
|
2619
2655
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
@@ -3325,7 +3361,7 @@ function buildPiUsereqToolToggleChoices(pi: ExtensionAPI, config: UseReqConfig):
|
|
|
3325
3361
|
|
|
3326
3362
|
/**
|
|
3327
3363
|
* @brief Runs the interactive active-tool configuration menu.
|
|
3328
|
-
* @details Synchronizes runtime active tools with
|
|
3364
|
+
* @details Synchronizes runtime active tools with the effective config, renders startup-tool actions through the shared settings-menu UI, persists enablement changes into global configuration, preserves the documented per-tool ordering, and updates configuration state in response to selections until the user exits. Runtime depends on user interaction count. Side effects include UI updates, active-tool changes, and config mutation.
|
|
3329
3365
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
3330
3366
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
3331
3367
|
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
@@ -3599,7 +3635,7 @@ function buildConfiguredStaticCheckLanguageChoices(config: UseReqConfig): PiUser
|
|
|
3599
3635
|
|
|
3600
3636
|
/**
|
|
3601
3637
|
* @brief Runs the interactive static-check configuration menu.
|
|
3602
|
-
* @details Lets the user add
|
|
3638
|
+
* @details Lets the user add and remove global Command entries, toggle direct local per-language enable flags, and reset the subtree to documented defaults through the shared settings-menu renderer until the user exits. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
3603
3639
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
3604
3640
|
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
3605
3641
|
* @return {Promise<void>} Promise resolved when the menu closes.
|
|
@@ -3755,11 +3791,11 @@ async function configureStaticCheckMenu(
|
|
|
3755
3791
|
|
|
3756
3792
|
/**
|
|
3757
3793
|
* @brief Builds the shared settings-menu choices for the top-level pi-usereq configuration UI.
|
|
3758
|
-
* @details Serializes primary configuration actions into right-valued menu rows consumed by the shared settings-menu renderer, including automatic git-commit mode, effective prompt-command worktree state, notification summary, debug summary, locked worktree rows when automatic git commit is disabled, and
|
|
3794
|
+
* @details Serializes primary configuration actions into right-valued menu rows consumed by the shared settings-menu renderer, including automatic git-commit mode, effective prompt-command worktree state, notification summary, debug summary, locked worktree rows when automatic git commit is disabled, and display-only local plus global config paths. Runtime is O(s) in source-directory count. No external state is mutated.
|
|
3759
3795
|
* @param[in] cwd {string} Current working directory.
|
|
3760
3796
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
3761
3797
|
* @return {PiUsereqSettingsMenuChoice[]} Ordered top-level menu choices.
|
|
3762
|
-
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-162, REQ-190, REQ-191, REQ-197, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240
|
|
3798
|
+
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-162, REQ-190, REQ-191, REQ-197, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-314, REQ-318, REQ-319, REQ-320
|
|
3763
3799
|
*/
|
|
3764
3800
|
function buildPiUsereqMenuChoices(
|
|
3765
3801
|
cwd: string,
|
|
@@ -3822,32 +3858,39 @@ function buildPiUsereqMenuChoices(
|
|
|
3822
3858
|
id: "static-check",
|
|
3823
3859
|
label: "Language static code checkers",
|
|
3824
3860
|
value: formatStaticCheckLanguagesSummary(config),
|
|
3825
|
-
description: "Manage
|
|
3861
|
+
description: "Manage global Command static-check entries and local per-language enable flags.",
|
|
3826
3862
|
},
|
|
3827
3863
|
{
|
|
3828
3864
|
id: "startup-tools",
|
|
3829
3865
|
label: "Enable tools",
|
|
3830
3866
|
value: `${getConfiguredEnabledPiUsereqTools(config).length} enabled`,
|
|
3831
|
-
description: "Manage
|
|
3867
|
+
description: "Manage the global configurable tool set activated during session_start.",
|
|
3832
3868
|
},
|
|
3833
3869
|
{
|
|
3834
3870
|
id: "notifications",
|
|
3835
3871
|
label: "Notifications",
|
|
3836
3872
|
value: `notification:${formatPiNotifyStatus(config)} • sound:${config["notify-sound"]} • pushover:${formatPiNotifyPushoverStatus(config)}`,
|
|
3837
|
-
description: "Manage command-notify, sound, and Pushover settings with dedicated event submenus.",
|
|
3873
|
+
description: "Manage global command-notify, sound, and Pushover settings with dedicated event submenus.",
|
|
3838
3874
|
},
|
|
3839
3875
|
{
|
|
3840
3876
|
id: "debug",
|
|
3841
3877
|
label: "Debug",
|
|
3842
3878
|
value: formatDebugMenuSummary(config),
|
|
3843
|
-
description: "Manage debug logging for tools and `req-*` prompt orchestration.",
|
|
3879
|
+
description: "Manage project-local debug logging for tools and `req-*` prompt orchestration.",
|
|
3880
|
+
},
|
|
3881
|
+
{
|
|
3882
|
+
id: "show-local-config",
|
|
3883
|
+
label: "Show local configuration",
|
|
3884
|
+
value: formatLocalConfigPathForMenu(cwd),
|
|
3885
|
+
valueTone: "dim",
|
|
3886
|
+
description: "Persist pending configuration changes and write the exact local config file text into the editor.",
|
|
3844
3887
|
},
|
|
3845
3888
|
{
|
|
3846
|
-
id: "show-config",
|
|
3847
|
-
label: "Show configuration",
|
|
3848
|
-
value:
|
|
3889
|
+
id: "show-global-config",
|
|
3890
|
+
label: "Show global configuration",
|
|
3891
|
+
value: formatGlobalConfigPathForMenu(),
|
|
3849
3892
|
valueTone: "dim",
|
|
3850
|
-
description: "Persist
|
|
3893
|
+
description: "Persist pending configuration changes and write the exact global config file text into the editor.",
|
|
3851
3894
|
},
|
|
3852
3895
|
...buildTerminalSettingsMenuChoices({
|
|
3853
3896
|
resetDefaultsDescription: "Restore the default pi-usereq configuration for the current project base.",
|
|
@@ -3905,12 +3948,12 @@ function buildSrcDirRemovalChoices(config: UseReqConfig): PiUsereqSettingsMenuCh
|
|
|
3905
3948
|
|
|
3906
3949
|
/**
|
|
3907
3950
|
* @brief Runs the top-level pi-usereq configuration menu.
|
|
3908
|
-
* @details Loads
|
|
3951
|
+
* @details Loads the effective merged config, exposes docs/test/source/automatic-commit/worktree/static-check/startup-tool/notification/debug actions through the shared settings-menu renderer, forces worktree disablement when automatic git commit is disabled, prevents locked row edits, persists changes on exit, closes immediately after `Show local configuration` or `Show global configuration`, and refreshes the single-line status bar. Runtime depends on user interaction count. Side effects include UI updates, config writes, active-tool changes, and editor text updates.
|
|
3909
3952
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
3910
3953
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
3911
3954
|
* @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
|
|
3912
3955
|
* @return {Promise<void>} Promise resolved when configuration is saved and the menu closes.
|
|
3913
|
-
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154, REQ-162, REQ-190, REQ-191, REQ-192, REQ-194, REQ-195, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-241, REQ-242, REQ-243
|
|
3956
|
+
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154, REQ-162, REQ-190, REQ-191, REQ-192, REQ-194, REQ-195, REQ-204, REQ-205, REQ-212, REQ-215, REQ-216, REQ-236, REQ-237, REQ-238, REQ-239, REQ-240, REQ-241, REQ-242, REQ-243, REQ-314, REQ-318, REQ-319, REQ-320
|
|
3914
3957
|
*/
|
|
3915
3958
|
async function configurePiUsereq(
|
|
3916
3959
|
pi: ExtensionAPI,
|
|
@@ -4152,12 +4195,16 @@ async function configurePiUsereq(
|
|
|
4152
4195
|
ctx.ui.notify("Restored all default configuration values", "info");
|
|
4153
4196
|
continue;
|
|
4154
4197
|
}
|
|
4155
|
-
if (choice === "show-config") {
|
|
4198
|
+
if (choice === "show-local-config" || choice === "show-global-config") {
|
|
4156
4199
|
persistConfigChange();
|
|
4157
4200
|
if (config["notify-sound-toggle-shortcut"] !== initialShortcut) {
|
|
4158
4201
|
ctx.ui.notify("Sound toggle hotkey bind updated; run /reload to apply the new binding", "info");
|
|
4159
4202
|
}
|
|
4160
|
-
|
|
4203
|
+
if (choice === "show-local-config") {
|
|
4204
|
+
writePersistedLocalConfigToEditor(ctx, ctx.cwd);
|
|
4205
|
+
} else {
|
|
4206
|
+
writePersistedGlobalConfigToEditor(ctx);
|
|
4207
|
+
}
|
|
4161
4208
|
return;
|
|
4162
4209
|
}
|
|
4163
4210
|
}
|
|
@@ -14,11 +14,13 @@ import { detectLanguage } from "../src/core/generate-markdown.js";
|
|
|
14
14
|
import { LANGUAGE_TAGS } from "../src/core/find-constructs.js";
|
|
15
15
|
import {
|
|
16
16
|
createStaticCheckLanguageConfig,
|
|
17
|
-
|
|
17
|
+
getDefaultConfig,
|
|
18
18
|
type UseReqConfig,
|
|
19
19
|
} from "../src/core/config.js";
|
|
20
20
|
import {
|
|
21
21
|
initFixtureRepo,
|
|
22
|
+
readGlobalConfigJson,
|
|
23
|
+
readProjectConfigJson,
|
|
22
24
|
runNodeCli,
|
|
23
25
|
runPythonCli,
|
|
24
26
|
runPythonInline,
|
|
@@ -450,10 +452,14 @@ function buildProjectScenarios(): AttendedScenario[] {
|
|
|
450
452
|
normalize: createProjectNormalizer(projectBase),
|
|
451
453
|
cleanup: () => removePath(projectBase),
|
|
452
454
|
postAssert: () => {
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
+
const defaultConfig = getDefaultConfig(projectBase);
|
|
456
|
+
const localPayload = readProjectConfigJson(projectBase) as unknown as Record<string, unknown>;
|
|
457
|
+
const globalPayload = readGlobalConfigJson() as unknown as Record<string, unknown>;
|
|
458
|
+
assert.equal((localPayload["static-check"] as Record<string, any>).Python.enabled, "enable");
|
|
459
|
+
assert.deepEqual((globalPayload["static-check"] as Record<string, any>).Python.checkers, [
|
|
460
|
+
...defaultConfig["static-check"].Python.checkers,
|
|
455
461
|
{ module: "Command", cmd: "git", params: ["--version"] },
|
|
456
|
-
]
|
|
462
|
+
]);
|
|
457
463
|
},
|
|
458
464
|
};
|
|
459
465
|
},
|
|
@@ -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
|
|
119
|
-
* @details Reads the raw project config JSON so tests can assert
|
|
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
|
|
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
|
-
|
|
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"), [
|
|
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"), [
|
|
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 {
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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",
|