pi-usereq 0.32.0 → 0.34.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/.github/workflows/release-npm.yml +3 -7
- package/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/pi-usereq/docs/REFERENCES.md +187 -187
- package/pi-usereq/docs/REQUIREMENTS.md +8 -8
- package/pi-usereq/docs/WORKFLOW.md +3 -3
- package/src/index.ts +17 -12
- package/tests/extension-registration.test.ts +31 -9
- package/tests/release-workflow.test.ts +61 -0
|
@@ -383,11 +383,11 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
|
|
|
383
383
|
- **REQ-152**: MUST render a persistent bottom-line description for the currently selected configuration entry.
|
|
384
384
|
- **REQ-153**: MUST use scrollable configuration menus when entry count exceeds the visible row budget.
|
|
385
385
|
- **REQ-154**: MUST wrap configuration-menu selection from last-to-first and first-to-last entries.
|
|
386
|
-
- **REQ-321**: MUST render `Enable debug commands for tools` in `Debug` after `Log file
|
|
386
|
+
- **REQ-321**: MUST render `Enable debug commands for tools` in `Debug` after `Debug`, before `Log file`, and before `Log on status`.
|
|
387
387
|
- **REQ-322**: MUST persist `DEBUG_TOOL_COMMANDS_ENABLED` through the `Debug` submenu with immediate-save, reset, and focus-preserving re-render behavior.
|
|
388
|
-
- **REQ-323**: MUST register `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` only when `DEBUG_TOOL_COMMANDS_ENABLED=enable`.
|
|
389
|
-
- **REQ-324**: MUST make `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` reuse the `compress`, `references`, `static-check`, and `tokens` runner outputs and write `content[0].text` to the editor.
|
|
390
|
-
- **REQ-325**: MUST reject `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` execution when `DEBUG_TOOL_COMMANDS_ENABLED=disable`.
|
|
388
|
+
- **REQ-323**: MUST register `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` only when `DEBUG_TOOL_COMMANDS_ENABLED=enable`.
|
|
389
|
+
- **REQ-324**: MUST make `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` reuse the `compress`, `references`, `static-check`, `summarize`, and `tokens` runner outputs and write `content[0].text` to the editor.
|
|
390
|
+
- **REQ-325**: MUST reject `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` execution when `DEBUG_TOOL_COMMANDS_ENABLED=disable`.
|
|
391
391
|
|
|
392
392
|
## 4. Test Requirements
|
|
393
393
|
- **TST-001**: MUST verify extension activation registers every documented prompt command, agent tool, and configuration command while omitting tool-name slash commands, `test-static-check`, and the removed standalone config-viewer command.
|
|
@@ -461,7 +461,7 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
|
|
|
461
461
|
- **TST-027**: MUST verify harness inspection surfaces `files-compress` and `compress` descriptions covering parameters, line-number behavior, monolithic markdown output, and failure details.
|
|
462
462
|
- **TST-028**: MUST verify `files-static-check` and `static-check` agent-tool outputs place the monolithic static-check report in `content[0].text` and restrict `details` to execution metadata.
|
|
463
463
|
- **TST-029**: MUST verify harness inspection surfaces `files-static-check` and `static-check` descriptions covering parameters, monolithic output, selection rules, and failure details.
|
|
464
|
-
- **TST-039**: MUST verify `.github/workflows/release-npm.yml` keeps the existing tag filter, gates downstream release work on `origin/master`, uses Node.js `24.15.0`, runs npm publication, and creates the GitHub Release
|
|
464
|
+
- **TST-039**: MUST verify `.github/workflows/release-npm.yml` parses as YAML when `PyYAML` is available, keeps the existing tag filter, gates downstream release work on `origin/master`, uses Node.js `24.15.0`, runs npm publication, and creates the GitHub Release.
|
|
465
465
|
- **TST-042**: MUST verify `package.json` keeps `name` equal to `pi-usereq` so npm publication resolves to `https://www.npmjs.com/package/pi-usereq`.
|
|
466
466
|
- **TST-044**: MUST verify `package.json` keeps npm provenance metadata aligned to the canonical GitHub repository, issues URL, and README homepage.
|
|
467
467
|
- **TST-040**: MUST verify local and global configuration files omit derived static and dynamic path fields while runtime path context and status rendering still derive them correctly.
|
|
@@ -500,10 +500,10 @@ PI-useReq is a TypeScript pi extension plus companion Node CLI and standalone ex
|
|
|
500
500
|
- **TST-066**: MUST verify `req-<prompt>` commands keep working when extension custom-tool registrations are removed from the runtime inventory.
|
|
501
501
|
- **TST-059**: MUST verify every agent-tool registration defines custom `renderResult` and that compact rendering shows essential invocation parameters while expanded rendering avoids fallback raw-content display.
|
|
502
502
|
- **TST-086**: MUST verify bundled prompt-backed `req-<prompt>` commands abort before prompt dispatch when the persisted execution-session header cwd or `process.cwd()` differs from the expected execution path, and abort before merge when persisted execution-session header metadata or verified worktree artifacts diverge, while stale pre-switch context probes alone do not abort.
|
|
503
|
-
- **TST-113**: MUST verify default local configuration persists `DEBUG_TOOL_COMMANDS_ENABLED=disable`, and the `Debug` submenu renders `Enable debug commands for tools` before `Log
|
|
503
|
+
- **TST-113**: MUST verify default local configuration persists `DEBUG_TOOL_COMMANDS_ENABLED=disable`, and the `Debug` submenu renders `Enable debug commands for tools` before `Log file`.
|
|
504
504
|
- **TST-114**: MUST verify the `Debug` submenu persists `DEBUG_TOOL_COMMANDS_ENABLED` through immediate-save, reset, and focus-preserving re-render flows.
|
|
505
|
-
- **TST-115**: MUST verify extension activation registers `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` only when `DEBUG_TOOL_COMMANDS_ENABLED=enable`.
|
|
506
|
-
- **TST-116**: MUST verify `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` write the same `content[0].text` as `compress`, `references`, `static-check`, and `tokens`, and reject execution when disabled.
|
|
505
|
+
- **TST-115**: MUST verify extension activation registers `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` only when `DEBUG_TOOL_COMMANDS_ENABLED=enable`.
|
|
506
|
+
- **TST-116**: MUST verify `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` write the same `content[0].text` as `compress`, `references`, `static-check`, `summarize`, and `tokens`, and reject execution when disabled.
|
|
507
507
|
|
|
508
508
|
## 5. Observed Component Model
|
|
509
509
|
|
|
@@ -888,7 +888,7 @@
|
|
|
888
888
|
- `getProjectConfigPath(...)`: resolve config file path [`src/core/config.ts`]
|
|
889
889
|
- `getDefaultConfig(...)`: build default config [`src/core/config.ts`]
|
|
890
890
|
- `normalizeEnabledPiUsereqTools(...)`: canonicalize startup tools [`src/core/pi-usereq-tools.ts`]
|
|
891
|
-
- `registerDebugToolCommands(...)`: register config-gated debug slash-command wrappers for `compress`, `references`, `static-check`, and `tokens` [`src/index.ts`]
|
|
891
|
+
- `registerDebugToolCommands(...)`: register config-gated debug slash-command wrappers for `compress`, `references`, `static-check`, `summarize`, and `tokens` [`src/index.ts`]
|
|
892
892
|
- `registerAgentTools(...)`: register structured pi tools whose execute callbacks reuse internal runner families, the status-only references writer, token-optimized payload builders, and compact-plus-expanded custom result renderers [`src/index.ts`]
|
|
893
893
|
- `ensureBundledResourcesAccessible(...)`: validate installation-owned bundled resources for tool executes that need bundled assets [`src/core/resources.ts`]
|
|
894
894
|
- `getBundledResourceRoot(...)`: resolve installation-owned resource root [`src/core/resources.ts`]
|
|
@@ -1193,10 +1193,10 @@
|
|
|
1193
1193
|
- `buildPiUsereqToolToggleChoices(...)`: serialize per-tool startup-toggle rows plus the value-less terminal reset action [`src/index.ts`]
|
|
1194
1194
|
- `buildTerminalSettingsMenuChoices(...)`: append the canonical value-less `Reset defaults` row to the selector menu [`src/index.ts`]
|
|
1195
1195
|
- `configureDebugMenu(...)`: interactive debug editor with in-place enable or disable toggles, tool-wrapper command registration, workflow filters, reset confirmation, and per-tool plus per-prompt selectors [`src/index.ts`]
|
|
1196
|
-
- `buildDebugMenuChoices(...)`: serialize global debug controls
|
|
1196
|
+
- `buildDebugMenuChoices(...)`: serialize global debug controls with `Enable debug commands for tools` before `Log file`, workflow-event toggles, canonical tool and prompt toggles, and the value-less terminal reset row [`src/index.ts`]
|
|
1197
1197
|
- `buildDebugMenuChoice(...)`: dim and disable locked debug rows while global debug is off [`src/index.ts`]
|
|
1198
1198
|
- `getDebugToolToggleNames(...)`: enumerate debuggable tool names in canonical grouped order [`src/index.ts`]
|
|
1199
|
-
- `registerDebugToolCommands(...)`: register debug slash-command wrappers immediately when the tool-wrapper row transitions to `enable` [`src/index.ts`]
|
|
1199
|
+
- `registerDebugToolCommands(...)`: register debug slash-command wrappers including `debug-summarize` immediately when the tool-wrapper row transitions to `enable` [`src/index.ts`]
|
|
1200
1200
|
- `selectDebugLogOnStatus(...)`: select one explicit workflow-state filter or `any` [`src/index.ts`]
|
|
1201
1201
|
- `confirmResetChanges(...)`: require explicit approval before applying reset mutations [`src/index.ts`]
|
|
1202
1202
|
- `resetDebugConfigToDefaults(...)`: restore the debug configuration subtree to documented defaults [`src/index.ts`]
|
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.34.0";
|
|
12
12
|
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
@@ -347,8 +347,8 @@ function executeDebugToolCommand(
|
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
/**
|
|
350
|
-
* @brief Registers config-gated debug slash-command wrappers for selected
|
|
351
|
-
* @details Registers `debug-compress`, `debug-references`, `debug-static-check`, and `debug-tokens` as extension commands that reuse the same runner paths as the corresponding agent tools and write the resulting monolithic text into the editor instead of the LLM content channel. Re-registering the same commands is idempotent because pi keeps the latest same-extension command definition per name. Runtime is O(1) for registration; handler cost depends on the selected runner. Side effects include command registration.
|
|
350
|
+
* @brief Registers config-gated debug slash-command wrappers for selected project analysis tools.
|
|
351
|
+
* @details Registers `debug-compress`, `debug-references`, `debug-static-check`, `debug-summarize`, and `debug-tokens` as extension commands that reuse the same runner paths as the corresponding agent tools and write the resulting monolithic text into the editor instead of the LLM content channel. Re-registering the same commands is idempotent because pi keeps the latest same-extension command definition per name. Runtime is O(1) for registration; handler cost depends on the selected runner. Side effects include command registration.
|
|
352
352
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
353
353
|
* @return {void} No return value.
|
|
354
354
|
* @satisfies DES-015, REQ-323, REQ-324, REQ-325
|
|
@@ -382,6 +382,11 @@ function registerDebugToolCommands(pi: ExtensionAPI): void {
|
|
|
382
382
|
"Run static-check and write the tool output into the editor",
|
|
383
383
|
(projectBase, config) => executeMonolithicTool(() => runProjectStaticCheck(projectBase, config)),
|
|
384
384
|
);
|
|
385
|
+
registerDebugToolCommand(
|
|
386
|
+
"debug-summarize",
|
|
387
|
+
"Run summarize and write the tool output into the editor",
|
|
388
|
+
(projectBase, config) => executeMonolithicTool(() => runSummarize(projectBase, config)),
|
|
389
|
+
);
|
|
385
390
|
registerDebugToolCommand(
|
|
386
391
|
"debug-tokens",
|
|
387
392
|
"Run tokens and write the tool output into the editor",
|
|
@@ -1643,20 +1648,20 @@ function buildDebugMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice
|
|
|
1643
1648
|
},
|
|
1644
1649
|
buildDebugMenuChoice(
|
|
1645
1650
|
{
|
|
1646
|
-
id: "debug-
|
|
1647
|
-
label: "
|
|
1648
|
-
value: config.
|
|
1649
|
-
|
|
1651
|
+
id: "debug-tool-commands-enabled",
|
|
1652
|
+
label: "Enable debug commands for tools",
|
|
1653
|
+
value: normalizeDebugToolCommandsEnabled(config.DEBUG_TOOL_COMMANDS_ENABLED),
|
|
1654
|
+
values: ["enable", "disable"],
|
|
1655
|
+
description: "Enable or disable slash-command wrappers for `compress`, `references`, `static-check`, `summarize`, and `tokens`.",
|
|
1650
1656
|
},
|
|
1651
1657
|
debugEnabled,
|
|
1652
1658
|
),
|
|
1653
1659
|
buildDebugMenuChoice(
|
|
1654
1660
|
{
|
|
1655
|
-
id: "debug-
|
|
1656
|
-
label: "
|
|
1657
|
-
value:
|
|
1658
|
-
|
|
1659
|
-
description: "Enable or disable slash-command wrappers for `compress`, `references`, `static-check`, and `tokens`.",
|
|
1661
|
+
id: "debug-log-file",
|
|
1662
|
+
label: "Log file",
|
|
1663
|
+
value: config.DEBUG_LOG_FILE,
|
|
1664
|
+
description: "Edit the JSON debug log file path. Relative paths resolve against the original project base.",
|
|
1660
1665
|
},
|
|
1661
1666
|
debugEnabled,
|
|
1662
1667
|
),
|
|
@@ -842,6 +842,7 @@ test("extension registers prompt and config commands while exposing tool capabil
|
|
|
842
842
|
"debug-compress",
|
|
843
843
|
"debug-references",
|
|
844
844
|
"debug-static-check",
|
|
845
|
+
"debug-summarize",
|
|
845
846
|
"debug-tokens",
|
|
846
847
|
"pi-usereq-show-config",
|
|
847
848
|
"test-static-check",
|
|
@@ -869,7 +870,7 @@ test("extension registers prompt and config commands while exposing tool capabil
|
|
|
869
870
|
|
|
870
871
|
/**
|
|
871
872
|
* @brief Verifies debug tool wrapper commands register only when the local debug flag is enabled.
|
|
872
|
-
* @details Activates the extension once from a default-disabled fixture and once from a fixture whose local config enables debug tool wrapper commands, then asserts the
|
|
873
|
+
* @details Activates the extension once from a default-disabled fixture and once from a fixture whose local config enables debug tool wrapper commands, then asserts the five debug slash commands appear only in the enabled runtime. Runtime is dominated by fixture setup and extension registration. Side effects are limited to temporary filesystem mutation and process cwd changes.
|
|
873
874
|
* @return {void} No return value.
|
|
874
875
|
* @throws {AssertionError} Throws when command registration ignores the local debug tool wrapper flag.
|
|
875
876
|
* @satisfies TST-115
|
|
@@ -881,6 +882,7 @@ test("debug tool commands register only when enabled in local config", () => {
|
|
|
881
882
|
"debug-compress",
|
|
882
883
|
"debug-references",
|
|
883
884
|
"debug-static-check",
|
|
885
|
+
"debug-summarize",
|
|
884
886
|
"debug-tokens",
|
|
885
887
|
];
|
|
886
888
|
|
|
@@ -1606,7 +1608,7 @@ test("static-check tools return monolithic text payloads with minimal execution
|
|
|
1606
1608
|
|
|
1607
1609
|
/**
|
|
1608
1610
|
* @brief Verifies debug tool wrapper commands mirror tool content and reject when disabled.
|
|
1609
|
-
* @details Enables debug tool wrapper commands for one fixture project, compares
|
|
1611
|
+
* @details Enables debug tool wrapper commands for one fixture project, compares the five debug slash-command editor payloads against the matching tool `content[0].text`, then disables the flag and verifies the already-registered wrappers reject further execution. Runtime is dominated by tool execution plus temporary git fixture setup. Side effects are limited to temporary filesystem mutation, editor-text capture, and process cwd changes.
|
|
1610
1612
|
* @return {Promise<void>} Promise resolved when the verification completes.
|
|
1611
1613
|
* @throws {AssertionError} Throws when a debug wrapper output diverges from the wrapped tool text or disabled execution is accepted.
|
|
1612
1614
|
* @satisfies TST-116
|
|
@@ -1643,6 +1645,9 @@ test("debug tool wrapper commands mirror tool content and reject when disabled",
|
|
|
1643
1645
|
const staticCheckToolResult = await executeRegisteredTool(pi, "static-check", projectBase) as {
|
|
1644
1646
|
content?: Array<{ type: string; text?: string }>;
|
|
1645
1647
|
};
|
|
1648
|
+
const summarizeToolResult = await executeRegisteredTool(pi, "summarize", projectBase, {}) as {
|
|
1649
|
+
content?: Array<{ type: string; text?: string }>;
|
|
1650
|
+
};
|
|
1646
1651
|
const tokensToolResult = await executeRegisteredTool(pi, "tokens", projectBase, {}) as {
|
|
1647
1652
|
content?: Array<{ type: string; text?: string }>;
|
|
1648
1653
|
};
|
|
@@ -1659,6 +1664,10 @@ test("debug tool wrapper commands mirror tool content and reject when disabled",
|
|
|
1659
1664
|
await pi.commands.get("debug-static-check")!.handler("", staticCheckCtx);
|
|
1660
1665
|
assert.equal(staticCheckCtx.__state.editorText, staticCheckToolResult.content?.[0]?.text ?? "");
|
|
1661
1666
|
|
|
1667
|
+
const summarizeCtx = createFakeCtx(projectBase);
|
|
1668
|
+
await pi.commands.get("debug-summarize")!.handler("", summarizeCtx);
|
|
1669
|
+
assert.equal(summarizeCtx.__state.editorText, summarizeToolResult.content?.[0]?.text ?? "");
|
|
1670
|
+
|
|
1662
1671
|
const tokensCtx = createFakeCtx(projectBase);
|
|
1663
1672
|
await pi.commands.get("debug-tokens")!.handler("", tokensCtx);
|
|
1664
1673
|
assert.equal(tokensCtx.__state.editorText, tokensToolResult.content?.[0]?.text ?? "");
|
|
@@ -1666,12 +1675,20 @@ test("debug tool wrapper commands mirror tool content and reject when disabled",
|
|
|
1666
1675
|
writeProjectConfigOverrides(projectBase, {
|
|
1667
1676
|
DEBUG_TOOL_COMMANDS_ENABLED: "disable",
|
|
1668
1677
|
});
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1678
|
+
for (const commandName of [
|
|
1679
|
+
"debug-compress",
|
|
1680
|
+
"debug-references",
|
|
1681
|
+
"debug-static-check",
|
|
1682
|
+
"debug-summarize",
|
|
1683
|
+
"debug-tokens",
|
|
1684
|
+
]) {
|
|
1685
|
+
const disabledCtx = createFakeCtx(projectBase);
|
|
1686
|
+
await assert.rejects(
|
|
1687
|
+
async () => pi.commands.get(commandName)!.handler("", disabledCtx),
|
|
1688
|
+
/disabled by Debug > Enable debug commands for tools/u,
|
|
1689
|
+
);
|
|
1690
|
+
assert.equal(disabledCtx.__state.editorText, "");
|
|
1691
|
+
}
|
|
1675
1692
|
} finally {
|
|
1676
1693
|
process.chdir(previousCwd);
|
|
1677
1694
|
fs.rmSync(projectBase, { recursive: true, force: true });
|
|
@@ -1968,6 +1985,10 @@ test("debug menu dims locked rows and persists debug settings with focus-preserv
|
|
|
1968
1985
|
const debugCalls = ctx.__state.selectCalls.filter((call) => call.title === "Debug");
|
|
1969
1986
|
assert.match(renderedInitialDebugMenu, /<dim>Log file/);
|
|
1970
1987
|
assert.match(renderedInitialDebugMenu, /<dim>Enable debug commands for tools/);
|
|
1988
|
+
assert.ok(
|
|
1989
|
+
renderedInitialDebugMenu.indexOf("<dim>Enable debug commands for tools")
|
|
1990
|
+
< renderedInitialDebugMenu.indexOf("<dim>Log file"),
|
|
1991
|
+
);
|
|
1971
1992
|
assert.match(renderedInitialDebugMenu, /<dim>Log on status/);
|
|
1972
1993
|
assert.match(renderedInitialDebugMenu, /<dim>Status changes/);
|
|
1973
1994
|
assert.match(renderedInitialDebugMenu, /<dim>Workflow events/);
|
|
@@ -1981,6 +2002,7 @@ test("debug menu dims locked rows and persists debug settings with focus-preserv
|
|
|
1981
2002
|
assert.ok(pi.commands.get("debug-compress"));
|
|
1982
2003
|
assert.ok(pi.commands.get("debug-references"));
|
|
1983
2004
|
assert.ok(pi.commands.get("debug-static-check"));
|
|
2005
|
+
assert.ok(pi.commands.get("debug-summarize"));
|
|
1984
2006
|
assert.ok(pi.commands.get("debug-tokens"));
|
|
1985
2007
|
assert.deepEqual(persistedConfig.DEBUG_ENABLED_TOOLS, ["files-tokens"]);
|
|
1986
2008
|
assert.deepEqual(persistedConfig.DEBUG_ENABLED_PROMPTS, ["req-analyze"]);
|
|
@@ -2023,8 +2045,8 @@ test("debug menu rows derive from canonical tool and prompt inventories", async
|
|
|
2023
2045
|
|
|
2024
2046
|
assert.deepEqual(ctx.__state.selectCalls[1]?.items ?? [], [
|
|
2025
2047
|
"Debug",
|
|
2026
|
-
"Log file",
|
|
2027
2048
|
"Enable debug commands for tools",
|
|
2049
|
+
"Log file",
|
|
2028
2050
|
"Log on status",
|
|
2029
2051
|
"Status changes",
|
|
2030
2052
|
"Workflow events",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import test from "node:test";
|
|
@@ -16,6 +17,61 @@ function readReleaseWorkflow(): string {
|
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @brief Verifies the release workflow YAML parses successfully via Python.
|
|
22
|
+
* @details Resolves a project-local `.venv/bin/python` first, then falls back to `python` and `python3`, executes an inline `yaml.safe_load(...)` check against `.github/workflows/release-npm.yml`, accepts the `PyYAML not available` skip path, and fails on non-zero exit status or `YAML ERROR` output. Runtime is dominated by subprocess probing and one Python execution. Side effects are limited to subprocess creation and filesystem reads performed by the Python snippet.
|
|
23
|
+
* @return {void} No return value.
|
|
24
|
+
* @throws {AssertionError} Throws when no usable Python interpreter exists or the workflow YAML fails to parse.
|
|
25
|
+
* @satisfies TST-039
|
|
26
|
+
*/
|
|
27
|
+
function assertReleaseWorkflowYamlSyntax(): void {
|
|
28
|
+
const workflowPath = path.join(
|
|
29
|
+
process.cwd(),
|
|
30
|
+
".github",
|
|
31
|
+
"workflows",
|
|
32
|
+
"release-npm.yml",
|
|
33
|
+
);
|
|
34
|
+
const pythonCandidates = [
|
|
35
|
+
path.join(process.cwd(), ".venv", "bin", "python"),
|
|
36
|
+
"python",
|
|
37
|
+
"python3",
|
|
38
|
+
];
|
|
39
|
+
const pythonCommand = pythonCandidates.find((candidate) => {
|
|
40
|
+
if (candidate.includes(path.sep) && !fs.existsSync(candidate)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
const probe = spawnSync(candidate, ["--version"], { encoding: "utf8" });
|
|
44
|
+
return !probe.error && probe.status === 0;
|
|
45
|
+
});
|
|
46
|
+
assert.ok(pythonCommand, "python executable not found for release workflow validation");
|
|
47
|
+
|
|
48
|
+
const pythonCode = [
|
|
49
|
+
"from pathlib import Path",
|
|
50
|
+
"import sys",
|
|
51
|
+
`p = Path(${JSON.stringify(workflowPath)})`,
|
|
52
|
+
"text = p.read_text()",
|
|
53
|
+
"try:",
|
|
54
|
+
" import yaml",
|
|
55
|
+
"except Exception as error:",
|
|
56
|
+
" print(f'PyYAML not available: {error}')",
|
|
57
|
+
" sys.exit(0)",
|
|
58
|
+
"try:",
|
|
59
|
+
" yaml.safe_load(text)",
|
|
60
|
+
" print('YAML OK')",
|
|
61
|
+
"except Exception as error:",
|
|
62
|
+
" print(f'YAML ERROR: {error}')",
|
|
63
|
+
" sys.exit(1)",
|
|
64
|
+
].join("\n");
|
|
65
|
+
const result = spawnSync(pythonCommand, ["-c", pythonCode], {
|
|
66
|
+
cwd: process.cwd(),
|
|
67
|
+
encoding: "utf8",
|
|
68
|
+
});
|
|
69
|
+
const output = `${result.stdout}${result.stderr}`;
|
|
70
|
+
|
|
71
|
+
assert.equal(result.status, 0, output || result.error?.message || "unknown python execution failure");
|
|
72
|
+
assert.doesNotMatch(output, /YAML ERROR:/u);
|
|
73
|
+
}
|
|
74
|
+
|
|
19
75
|
/**
|
|
20
76
|
* @brief Describes the package manifest fields asserted by npm release tests.
|
|
21
77
|
* @details Constrains the parsed `package.json` shape to the publication identity and provenance metadata required by the release workflow tests. The interface is compile-time only and introduces no runtime side effects.
|
|
@@ -75,6 +131,11 @@ function assertCanonicalPackageProvenanceMetadata(): void {
|
|
|
75
131
|
assert.equal(manifest.homepage, "https://github.com/Ogekuri/PI-useReq#readme");
|
|
76
132
|
}
|
|
77
133
|
|
|
134
|
+
test(
|
|
135
|
+
"release workflow remains valid YAML when parsed by Python",
|
|
136
|
+
assertReleaseWorkflowYamlSyntax,
|
|
137
|
+
);
|
|
138
|
+
|
|
78
139
|
test(
|
|
79
140
|
"release workflow keeps the current tag trigger and gates release work on origin/master ancestry",
|
|
80
141
|
() => {
|