pi-usereq 0.4.0 → 0.6.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/.gitignore +3 -0
- package/CHANGELOG.md +41 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/{req → pi-usereq}/docs/REFERENCES.md +499 -491
- package/{req → pi-usereq}/docs/REQUIREMENTS.md +84 -62
- package/{req → pi-usereq}/docs/WORKFLOW.md +87 -102
- package/src/core/agent-tool-json.ts +42 -193
- package/src/core/compress-payload.ts +7 -15
- package/src/core/config.ts +39 -12
- package/src/core/extension-status.ts +94 -58
- package/src/core/find-payload.ts +21 -44
- package/src/core/pi-notify.ts +198 -11
- package/src/core/reference-payload.ts +6 -14
- package/src/core/runtime-project-paths.ts +3 -32
- package/src/core/settings-menu.ts +9 -4
- package/src/core/static-check.ts +35 -171
- package/src/core/token-counter.ts +3 -121
- package/src/index.ts +339 -180
- package/tests/attended-results-scenarios.ts +3 -13
- package/tests/cli-command-option-parity.test.ts +21 -12
- package/tests/debug-extension-harness.test.ts +20 -22
- package/tests/extension-registration.test.ts +394 -157
- package/tests/oracle-project.test.ts +8 -3
- package/tests/oracle-standalone.test.ts +7 -13
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_c.c.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_cpp.cpp.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_csharp.cs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_elixir.ex.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_go.go.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_haskell.hs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_java.java.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_javascript.js.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_kotlin.kt.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_lua.lua.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_perl.pl.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_php.php.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_python.py.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_ruby.rb.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_rust.rs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_scala.scala.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_shell.sh.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_swift.swift.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_typescript.ts.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-pylance/fixture_zig.zig.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_c.c.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_cpp.cpp.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_csharp.cs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_elixir.ex.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_go.go.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_haskell.hs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_java.java.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_javascript.js.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_kotlin.kt.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_lua.lua.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_perl.pl.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_php.php.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_python.py.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_ruby.rb.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_rust.rs.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_scala.scala.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_shell.sh.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_swift.swift.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_typescript.ts.json +0 -5
- package/tests/fixtures_attended_results/standalone/test-static-check-ruff/fixture_zig.zig.json +0 -5
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.6.0"
|
|
12
12
|
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import type {
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
} from "./core/find-payload.js";
|
|
54
54
|
import {
|
|
55
55
|
getDefaultConfig,
|
|
56
|
+
getProjectConfigPath,
|
|
56
57
|
loadConfig,
|
|
57
58
|
normalizeConfigPaths,
|
|
58
59
|
saveConfig,
|
|
@@ -62,10 +63,15 @@ import {
|
|
|
62
63
|
import {
|
|
63
64
|
cyclePiNotifySoundLevel,
|
|
64
65
|
formatPiNotifyBeepStatus,
|
|
66
|
+
formatPiNotifyPushoverStatus,
|
|
67
|
+
normalizePiNotifyPushoverCredential,
|
|
68
|
+
normalizePiNotifyPushoverPriority,
|
|
65
69
|
runPiNotifyEffects,
|
|
70
|
+
type PiNotifyPushoverPriority,
|
|
71
|
+
type PiNotifyPushoverRequest,
|
|
66
72
|
type PiNotifySoundLevel,
|
|
67
73
|
} from "./core/pi-notify.js";
|
|
68
|
-
import {
|
|
74
|
+
import { formatRuntimePathForDisplay } from "./core/path-context.js";
|
|
69
75
|
import { resolveRuntimeGitPath } from "./core/runtime-project-paths.js";
|
|
70
76
|
import { showPiUsereqSettingsMenu, type PiUsereqSettingsMenuChoice } from "./core/settings-menu.js";
|
|
71
77
|
import {
|
|
@@ -154,20 +160,6 @@ function getProjectBase(cwd: string): string {
|
|
|
154
160
|
return path.resolve(cwd);
|
|
155
161
|
}
|
|
156
162
|
|
|
157
|
-
/**
|
|
158
|
-
* @brief Builds the shared runtime path facts for the current command or tool context.
|
|
159
|
-
* @details Derives installation, execution, base, config, resource, docs, test, source, and optional git paths from the cwd-derived project configuration plus runtime-only repository probing, then converts them into prompt/tool-facing strings. Runtime is O(s + p) where s is configured source-directory count and p is aggregate path length. Side effects are limited to git subprocess execution.
|
|
160
|
-
* @param[in] cwd {string} Current working directory.
|
|
161
|
-
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
162
|
-
* @return {import("./core/path-context.js").RuntimePathFacts} Shared runtime path facts.
|
|
163
|
-
* @satisfies REQ-145, REQ-146
|
|
164
|
-
*/
|
|
165
|
-
function buildSharedRuntimePathFacts(cwd: string, config: UseReqConfig): import("./core/path-context.js").RuntimePathFacts {
|
|
166
|
-
const projectBase = getProjectBase(cwd);
|
|
167
|
-
const gitPath = resolveRuntimeGitPath(projectBase);
|
|
168
|
-
return buildRuntimePathFacts(buildRuntimePathContext(projectBase, config, { gitPath }));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
163
|
/**
|
|
172
164
|
* @brief Loads project configuration for the extension runtime.
|
|
173
165
|
* @details Resolves the project base, loads persisted config, and normalizes configured directory paths without reading or persisting runtime-derived `base-path` or `git-path` metadata. Runtime is dominated by config I/O. Side effects are limited to filesystem reads.
|
|
@@ -193,6 +185,19 @@ function saveProjectConfig(cwd: string, config: UseReqConfig): void {
|
|
|
193
185
|
saveConfig(projectBase, normalizeConfigPaths(projectBase, config));
|
|
194
186
|
}
|
|
195
187
|
|
|
188
|
+
/**
|
|
189
|
+
* @brief Formats the current project config path for top-level menu display.
|
|
190
|
+
* @details Resolves `<base-path>/.pi-usereq/config.json` from the cwd-derived
|
|
191
|
+
* project base and formats it relative to the user home when possible. Runtime
|
|
192
|
+
* is O(p) in path length. No external state is mutated.
|
|
193
|
+
* @param[in] cwd {string} Current working directory.
|
|
194
|
+
* @return {string} User-home-relative or absolute config path display value.
|
|
195
|
+
* @satisfies REQ-162
|
|
196
|
+
*/
|
|
197
|
+
function formatProjectConfigPathForMenu(cwd: string): string {
|
|
198
|
+
return formatRuntimePathForDisplay(getProjectConfigPath(getProjectBase(cwd)));
|
|
199
|
+
}
|
|
200
|
+
|
|
196
201
|
/**
|
|
197
202
|
* @brief Collects the project-scoped static-check selection used by the agent tool.
|
|
198
203
|
* @details Resolves configured source plus test directories, reuses the same fixture-root exclusions as `runProjectStaticCheck`, and returns canonical relative file paths for structured payload emission. Runtime is O(F) plus project file-discovery cost. Side effects are limited to filesystem reads and git subprocesses delegated through `collectSourceFiles`.
|
|
@@ -240,10 +245,12 @@ function collectProjectStaticCheckSelection(
|
|
|
240
245
|
* @return {string} Newline-delimited execution diagnostics.
|
|
241
246
|
*/
|
|
242
247
|
function buildTokenToolExecutionStderr(payload: TokenToolPayload): string {
|
|
243
|
-
const skippedLines = payload.
|
|
244
|
-
.
|
|
245
|
-
|
|
246
|
-
|
|
248
|
+
const skippedLines = payload.files
|
|
249
|
+
.filter((entry) => entry.status === "skipped" && entry.error_message)
|
|
250
|
+
.map((entry) => `skipped: ${entry.canonical_path}: ${entry.error_message!}`);
|
|
251
|
+
const errorLines = payload.files
|
|
252
|
+
.filter((entry) => entry.status === "error" && entry.error_message)
|
|
253
|
+
.map((entry) => `error: ${entry.canonical_path}: ${entry.error_message!}`);
|
|
247
254
|
return [...skippedLines, ...errorLines].join("\n");
|
|
248
255
|
}
|
|
249
256
|
|
|
@@ -261,10 +268,8 @@ function buildTokenToolExecuteResult(
|
|
|
261
268
|
details: TokenToolPayload & { execution: { code: number; stderr: string } };
|
|
262
269
|
} {
|
|
263
270
|
const details = {
|
|
264
|
-
request: payload.request,
|
|
265
271
|
summary: payload.summary,
|
|
266
272
|
files: payload.files,
|
|
267
|
-
guidance: payload.guidance,
|
|
268
273
|
execution: {
|
|
269
274
|
code: payload.summary.counted_file_count > 0 ? 0 : 1,
|
|
270
275
|
stderr: buildTokenToolExecutionStderr(payload),
|
|
@@ -287,7 +292,6 @@ function buildReferenceToolExecuteResult(
|
|
|
287
292
|
details: ReferenceToolPayload & { execution: { code: number; stderr: string } };
|
|
288
293
|
} {
|
|
289
294
|
const details = {
|
|
290
|
-
request: payload.request,
|
|
291
295
|
summary: payload.summary,
|
|
292
296
|
repository: payload.repository,
|
|
293
297
|
files: payload.files,
|
|
@@ -313,7 +317,6 @@ function buildCompressionToolExecuteResult(
|
|
|
313
317
|
details: CompressToolPayload & { execution: { code: number; stderr: string } };
|
|
314
318
|
} {
|
|
315
319
|
const details = {
|
|
316
|
-
request: payload.request,
|
|
317
320
|
summary: payload.summary,
|
|
318
321
|
repository: payload.repository,
|
|
319
322
|
files: payload.files,
|
|
@@ -400,7 +403,7 @@ function buildFindToolSchemaDescription(scope: FindToolScope): string {
|
|
|
400
403
|
const inputContract = scope === "explicit-files"
|
|
401
404
|
? "Input contract: tag + pattern + files[] + optional enableLineNumbers."
|
|
402
405
|
: "Input contract: tag + pattern + optional enableLineNumbers. Scope is the configured src-dir list resolved from the current project configuration.";
|
|
403
|
-
return `${inputContract} Output contract: JSON object with
|
|
406
|
+
return `${inputContract} Output contract: JSON object with summary, repository, files, and execution. Static supported-tag matrices are documented in tool registration metadata instead of runtime responses. File entries expose structured statuses, file_doxygen, and match records with typed line ranges, stripped code lines, and structured Doxygen fields. Regex matches construct names only.`;
|
|
404
407
|
}
|
|
405
408
|
|
|
406
409
|
/**
|
|
@@ -414,13 +417,13 @@ function buildFindToolPromptGuidelines(scope: FindToolScope): string[] {
|
|
|
414
417
|
? "Scope: explicit source files selected by files[]; caller order is preserved; each item may be project-relative or absolute."
|
|
415
418
|
: "Scope: resolve src-dir from the current project configuration and scan the configured source surface from the current working directory.";
|
|
416
419
|
const outputLine = scope === "explicit-files"
|
|
417
|
-
? "Output contract:
|
|
418
|
-
: "Output contract:
|
|
420
|
+
? "Output contract: summary + repository + files + execution. Repository exposes requested file scope only when it adds dynamic search context; supported tags remain documented in registration metadata. File entries expose status, line ranges, file_doxygen, and matches; match entries expose symbol_kind, signature_text, line ranges, code_lines, stripped_source_text, and structured Doxygen fields."
|
|
421
|
+
: "Output contract: summary + repository + files + execution. Repository exposes source_directory_paths and file_canonical_paths when project-scope search context varies; supported tags remain documented in registration metadata. File entries expose status, line ranges, file_doxygen, and matches; match entries expose symbol_kind, signature_text, line ranges, code_lines, stripped_source_text, and structured Doxygen fields.";
|
|
419
422
|
return [
|
|
420
423
|
scopeLine,
|
|
421
424
|
outputLine,
|
|
422
425
|
"Regex rule: pattern is applied to construct names only with JavaScript RegExp search semantics; it never matches construct bodies; use ^...$ for exact-name matching.",
|
|
423
|
-
"Tag rule: tag is pipe-separated and case-insensitive; unsupported tags are ignored; if no valid tag remains,
|
|
426
|
+
"Tag rule: tag is pipe-separated and case-insensitive; unsupported tags are ignored; if no valid tag remains, the response search_status becomes invalid_tag_filter.",
|
|
424
427
|
"Line-number behavior: enableLineNumbers changes only display_text and stripped_source_text rendering; numeric source_line_number and line_range facts remain dedicated fields.",
|
|
425
428
|
"Failure contract: invalid tag filters, invalid regex patterns, unsupported extensions, unsupported tag-language combinations, no-match files, and analysis failures are surfaced as structured statuses plus optional execution.stderr diagnostics.",
|
|
426
429
|
...buildFindToolSupportedTagGuidelines(),
|
|
@@ -442,7 +445,6 @@ function buildFindToolExecuteResult(
|
|
|
442
445
|
} {
|
|
443
446
|
const stderr = buildFindToolExecutionStderr(payload);
|
|
444
447
|
const details = {
|
|
445
|
-
request: payload.request,
|
|
446
448
|
summary: payload.summary,
|
|
447
449
|
repository: payload.repository,
|
|
448
450
|
files: payload.files,
|
|
@@ -537,18 +539,20 @@ function applyConfiguredPiUsereqTools(pi: ExtensionAPI, config: UseReqConfig): v
|
|
|
537
539
|
* @details Applies session-start-specific resource validation, project-config
|
|
538
540
|
* refresh, and startup-tool enablement before forwarding the originating hook
|
|
539
541
|
* name and payload into the shared `updateExtensionStatus(...)` pipeline.
|
|
540
|
-
* On `agent_end`, also dispatches configured pi-notify beep
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
542
|
+
* On `agent_end`, also dispatches configured pi-notify beep, sound, and
|
|
543
|
+
* prompt-specific Pushover effects when the current run originates from a
|
|
544
|
+
* bundled prompt command. Runtime is dominated by configuration loading during
|
|
545
|
+
* `session_start`; all other hooks are O(1). Side effects include resource
|
|
546
|
+
* checks, active-tool mutation, status updates, live-ticker disposal on
|
|
547
|
+
* shutdown, stdout writes, optional child-process spawning, and outbound
|
|
548
|
+
* HTTPS requests.
|
|
545
549
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
546
550
|
* @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
|
|
547
551
|
* @param[in] hookName {PiUsereqStatusHookName} Intercepted hook name.
|
|
548
552
|
* @param[in] event {unknown} Hook payload forwarded by pi.
|
|
549
553
|
* @param[in] ctx {ExtensionContext} Active extension context.
|
|
550
554
|
* @return {Promise<void>} Promise resolved when hook processing completes.
|
|
551
|
-
* @satisfies REQ-117, REQ-118, REQ-119, REQ-129, REQ-130, REQ-131, REQ-132, REQ-133
|
|
555
|
+
* @satisfies REQ-117, REQ-118, REQ-119, REQ-129, REQ-130, REQ-131, REQ-132, REQ-133, REQ-166, REQ-167, REQ-168, REQ-169, REQ-172
|
|
552
556
|
*/
|
|
553
557
|
async function handleExtensionStatusEvent(
|
|
554
558
|
pi: ExtensionAPI,
|
|
@@ -564,8 +568,24 @@ async function handleExtensionStatusEvent(
|
|
|
564
568
|
setPiUsereqStatusConfig(statusController, config);
|
|
565
569
|
}
|
|
566
570
|
updateExtensionStatus(statusController, hookName, event, ctx);
|
|
567
|
-
if (hookName === "agent_end"
|
|
568
|
-
|
|
571
|
+
if (hookName === "agent_end") {
|
|
572
|
+
if (statusController.config) {
|
|
573
|
+
const pushoverRequest: PiNotifyPushoverRequest | undefined = statusController.state.activePromptRequest
|
|
574
|
+
&& statusController.state.lastRunDurationMs !== undefined
|
|
575
|
+
? {
|
|
576
|
+
promptName: statusController.state.activePromptRequest.promptName,
|
|
577
|
+
promptArgs: statusController.state.activePromptRequest.promptArgs,
|
|
578
|
+
basePath: path.resolve(ctx.cwd),
|
|
579
|
+
completionTimeMs: statusController.state.lastRunDurationMs,
|
|
580
|
+
}
|
|
581
|
+
: undefined;
|
|
582
|
+
runPiNotifyEffects(
|
|
583
|
+
statusController.config,
|
|
584
|
+
event as { messages: AgentEndEvent["messages"] },
|
|
585
|
+
pushoverRequest,
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
statusController.state.activePromptRequest = undefined;
|
|
569
589
|
}
|
|
570
590
|
if (hookName === "session_shutdown") {
|
|
571
591
|
disposePiUsereqStatusController(statusController);
|
|
@@ -671,12 +691,162 @@ function togglePiNotifyBeepFlag(config: UseReqConfig, key: PiNotifyBeepConfigKey
|
|
|
671
691
|
return config[key];
|
|
672
692
|
}
|
|
673
693
|
|
|
694
|
+
/**
|
|
695
|
+
* @brief Formats one persisted Pushover priority for menu display.
|
|
696
|
+
* @details Maps the canonical `0|1` priority domain to deterministic menu text reused by the Pushover configuration UI. Runtime is O(1). No external state is mutated.
|
|
697
|
+
* @param[in] priority {PiNotifyPushoverPriority} Persisted Pushover priority.
|
|
698
|
+
* @return {string} Menu-display label.
|
|
699
|
+
* @satisfies REQ-165
|
|
700
|
+
*/
|
|
701
|
+
function formatPiNotifyPushoverPriority(priority: PiNotifyPushoverPriority): string {
|
|
702
|
+
return priority === 1 ? "1=High Priority" : "0=Normal";
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* @brief Builds the shared settings-menu choices for Pushover configuration.
|
|
707
|
+
* @details Serializes the Pushover global-disable flag, successful-completion enable flag, credential strings, and priority value into right-valued menu rows consumed by the shared settings-menu renderer. Runtime is O(1). No external state is mutated.
|
|
708
|
+
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
709
|
+
* @return {PiUsereqSettingsMenuChoice[]} Ordered Pushover-menu choice vector.
|
|
710
|
+
* @satisfies REQ-163, REQ-165, REQ-166, REQ-172
|
|
711
|
+
*/
|
|
712
|
+
function buildPiNotifyPushoverMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice[] {
|
|
713
|
+
return [
|
|
714
|
+
{
|
|
715
|
+
id: "pushover-global-disable",
|
|
716
|
+
label: "Global disable",
|
|
717
|
+
value: config["notify-pushover-global-disable"] ? "on" : "off",
|
|
718
|
+
description: "Suppress all Pushover delivery without changing the successful-prompt enable flag.",
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
id: "pushover-on-success",
|
|
722
|
+
label: "Notify on success",
|
|
723
|
+
value: formatPiNotifyPushoverStatus(config),
|
|
724
|
+
description: "Toggle Pushover delivery after successful prompt completion only.",
|
|
725
|
+
},
|
|
726
|
+
{
|
|
727
|
+
id: "pushover-user-key",
|
|
728
|
+
label: "User Key/Delivery Group Key",
|
|
729
|
+
value: config["notify-pushover-user-key"] || "(empty)",
|
|
730
|
+
description: "Edit the Pushover user key or delivery group key sent with successful prompt notifications.",
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
id: "pushover-api-token",
|
|
734
|
+
label: "Token/API Token Key",
|
|
735
|
+
value: config["notify-pushover-api-token"] || "(empty)",
|
|
736
|
+
description: "Edit the Pushover application token used for successful prompt notifications.",
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
id: "pushover-priority",
|
|
740
|
+
label: "Priority",
|
|
741
|
+
value: formatPiNotifyPushoverPriority(config["notify-pushover-priority"]),
|
|
742
|
+
description: "Select whether successful prompt notifications use normal or high Pushover priority.",
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
id: "back",
|
|
746
|
+
label: "Back",
|
|
747
|
+
value: "",
|
|
748
|
+
description: "Return to the notifications menu.",
|
|
749
|
+
},
|
|
750
|
+
];
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* @brief Opens the shared settings-menu selector for Pushover priority.
|
|
755
|
+
* @details Reuses the pi-usereq settings-menu renderer so Pushover priority selection remains stylistically aligned with the existing notification menus and returns the chosen priority or `undefined` on cancel. Runtime depends on user interaction count. Side effects are limited to transient custom-UI rendering.
|
|
756
|
+
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
757
|
+
* @param[in] currentPriority {PiNotifyPushoverPriority} Persisted priority value.
|
|
758
|
+
* @return {Promise<PiNotifyPushoverPriority | undefined>} Selected priority or `undefined` when cancelled.
|
|
759
|
+
* @satisfies REQ-165
|
|
760
|
+
*/
|
|
761
|
+
async function selectPiNotifyPushoverPriority(
|
|
762
|
+
ctx: ExtensionCommandContext,
|
|
763
|
+
currentPriority: PiNotifyPushoverPriority,
|
|
764
|
+
): Promise<PiNotifyPushoverPriority | undefined> {
|
|
765
|
+
const choice = await showPiUsereqSettingsMenu(ctx, "Pushover priority", [
|
|
766
|
+
{
|
|
767
|
+
id: "0",
|
|
768
|
+
label: "0=Normal",
|
|
769
|
+
value: currentPriority === 0 ? "selected" : "",
|
|
770
|
+
description: "Send successful prompt notifications with normal Pushover priority.",
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
id: "1",
|
|
774
|
+
label: "1=High Priority",
|
|
775
|
+
value: currentPriority === 1 ? "selected" : "",
|
|
776
|
+
description: "Send successful prompt notifications with high Pushover priority.",
|
|
777
|
+
},
|
|
778
|
+
]);
|
|
779
|
+
if (!choice) {
|
|
780
|
+
return undefined;
|
|
781
|
+
}
|
|
782
|
+
return normalizePiNotifyPushoverPriority(choice);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* @brief Runs the interactive Pushover-configuration menu.
|
|
787
|
+
* @details Exposes the Pushover global-disable flag, successful-completion enable flag, user key, API token, and priority selector through the shared settings-menu renderer. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
788
|
+
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
789
|
+
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
790
|
+
* @return {Promise<void>} Promise resolved when the menu closes.
|
|
791
|
+
* @satisfies REQ-163, REQ-165, REQ-166, REQ-172
|
|
792
|
+
*/
|
|
793
|
+
async function configurePiNotifyPushoverMenu(
|
|
794
|
+
ctx: ExtensionCommandContext,
|
|
795
|
+
config: UseReqConfig,
|
|
796
|
+
): Promise<void> {
|
|
797
|
+
while (true) {
|
|
798
|
+
const choice = await showPiUsereqSettingsMenu(ctx, "Pushover notifications", buildPiNotifyPushoverMenuChoices(config));
|
|
799
|
+
if (!choice || choice === "back") {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (choice === "pushover-global-disable") {
|
|
803
|
+
config["notify-pushover-global-disable"] = !config["notify-pushover-global-disable"];
|
|
804
|
+
ctx.ui.notify(`Pushover global disable ${config["notify-pushover-global-disable"] ? "enabled" : "disabled"}`, "info");
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
if (choice === "pushover-on-success") {
|
|
808
|
+
config["notify-pushover-on-success"] = !config["notify-pushover-on-success"];
|
|
809
|
+
ctx.ui.notify(`Pushover on success ${config["notify-pushover-on-success"] ? "enabled" : "disabled"}`, "info");
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (choice === "pushover-user-key") {
|
|
813
|
+
const value = await ctx.ui.input(
|
|
814
|
+
"User Key/Delivery Group Key",
|
|
815
|
+
config["notify-pushover-user-key"] || "gzfjjvp1xxmhibqwzh9m7i1zwvf83j",
|
|
816
|
+
);
|
|
817
|
+
if (value !== undefined) {
|
|
818
|
+
config["notify-pushover-user-key"] = normalizePiNotifyPushoverCredential(value);
|
|
819
|
+
ctx.ui.notify("Updated Pushover user key", "info");
|
|
820
|
+
}
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
if (choice === "pushover-api-token") {
|
|
824
|
+
const value = await ctx.ui.input(
|
|
825
|
+
"Token/API Token Key",
|
|
826
|
+
config["notify-pushover-api-token"] || "ah6bf5u2sj63mcvou6qamiabeoubbe",
|
|
827
|
+
);
|
|
828
|
+
if (value !== undefined) {
|
|
829
|
+
config["notify-pushover-api-token"] = normalizePiNotifyPushoverCredential(value);
|
|
830
|
+
ctx.ui.notify("Updated Pushover API token", "info");
|
|
831
|
+
}
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
if (choice === "pushover-priority") {
|
|
835
|
+
const nextPriority = await selectPiNotifyPushoverPriority(ctx, config["notify-pushover-priority"]);
|
|
836
|
+
if (nextPriority !== undefined) {
|
|
837
|
+
config["notify-pushover-priority"] = nextPriority;
|
|
838
|
+
ctx.ui.notify(`Pushover priority set to ${formatPiNotifyPushoverPriority(nextPriority)}`, "info");
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
674
844
|
/**
|
|
675
845
|
* @brief Builds the shared settings-menu choices for notification configuration.
|
|
676
|
-
* @details Serializes the current beep flags, selected notify command, hotkey bind,
|
|
846
|
+
* @details Serializes the current beep flags, selected notify command, hotkey bind, per-level notify commands, and the Pushover submenu entry into right-valued menu rows consumed by the shared settings-menu renderer. Runtime is O(1) plus command-length formatting. No external state is mutated.
|
|
677
847
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
678
848
|
* @return {PiUsereqSettingsMenuChoice[]} Ordered notification-menu choice vector.
|
|
679
|
-
* @satisfies REQ-137, REQ-149, REQ-150, REQ-151, REQ-152
|
|
849
|
+
* @satisfies REQ-137, REQ-149, REQ-150, REQ-151, REQ-152, REQ-163, REQ-164, REQ-165, REQ-166, REQ-172
|
|
680
850
|
*/
|
|
681
851
|
function buildPiNotifyMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice[] {
|
|
682
852
|
return [
|
|
@@ -728,6 +898,12 @@ function buildPiNotifyMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuCho
|
|
|
728
898
|
value: config.PI_NOTIFY_SOUND_HIGH_CMD,
|
|
729
899
|
description: "Edit the shell command used when the selected notify command is `high`.",
|
|
730
900
|
},
|
|
901
|
+
{
|
|
902
|
+
id: "pushover-notifications",
|
|
903
|
+
label: "Pushover notifications",
|
|
904
|
+
value: formatPiNotifyPushoverStatus(config),
|
|
905
|
+
description: "Open the Pushover submenu for successful-completion delivery, credentials, priority, and global disable.",
|
|
906
|
+
},
|
|
731
907
|
{
|
|
732
908
|
id: "back",
|
|
733
909
|
label: "Back",
|
|
@@ -780,11 +956,11 @@ async function selectPiNotifySoundLevel(
|
|
|
780
956
|
|
|
781
957
|
/**
|
|
782
958
|
* @brief Runs the interactive notification-configuration menu.
|
|
783
|
-
* @details Exposes prompt-end beep toggles, selected notify-command selection, hotkey-bind editing,
|
|
959
|
+
* @details Exposes prompt-end beep toggles, selected notify-command selection, hotkey-bind editing, per-level notify-command editors, and the nested Pushover submenu through the shared settings-menu renderer. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
784
960
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
785
961
|
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
786
962
|
* @return {Promise<boolean>} `true` when the sound-toggle shortcut changed.
|
|
787
|
-
* @satisfies REQ-129, REQ-131, REQ-133, REQ-134, REQ-137, REQ-149, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154
|
|
963
|
+
* @satisfies REQ-129, REQ-131, REQ-133, REQ-134, REQ-137, REQ-149, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154, REQ-163, REQ-164, REQ-165, REQ-166, REQ-172
|
|
788
964
|
*/
|
|
789
965
|
async function configurePiNotifyMenu(
|
|
790
966
|
ctx: ExtensionCommandContext,
|
|
@@ -849,6 +1025,10 @@ async function configurePiNotifyMenu(
|
|
|
849
1025
|
config.PI_NOTIFY_SOUND_HIGH_CMD = value.trim();
|
|
850
1026
|
ctx.ui.notify("Updated notify command (high vol.)", "info");
|
|
851
1027
|
}
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
if (choice === "pushover-notifications") {
|
|
1031
|
+
await configurePiNotifyPushoverMenu(ctx, config);
|
|
852
1032
|
}
|
|
853
1033
|
}
|
|
854
1034
|
}
|
|
@@ -890,12 +1070,16 @@ function registerPiNotifyShortcut(
|
|
|
890
1070
|
|
|
891
1071
|
/**
|
|
892
1072
|
* @brief Registers bundled prompt commands with the extension.
|
|
893
|
-
* @details Creates one `req-<prompt>` command per bundled prompt name. Each handler ensures resources exist, renders the prompt, and sends it into the current active session. Runtime is O(p) for registration; handler cost depends on prompt rendering plus prompt dispatch. Side effects include command registration and user-message delivery during execution.
|
|
1073
|
+
* @details Creates one `req-<prompt>` command per bundled prompt name. Each handler ensures resources exist, records the prompt metadata needed for successful completion notifications, renders the prompt, and sends it into the current active session. Runtime is O(p) for registration; handler cost depends on prompt rendering plus prompt dispatch. Side effects include command registration, status-controller mutation, and user-message delivery during execution.
|
|
894
1074
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
1075
|
+
* @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
|
|
895
1076
|
* @return {void} No return value.
|
|
896
|
-
* @satisfies REQ-004, REQ-067, REQ-068
|
|
1077
|
+
* @satisfies REQ-004, REQ-067, REQ-068, REQ-169
|
|
897
1078
|
*/
|
|
898
|
-
function registerPromptCommands(
|
|
1079
|
+
function registerPromptCommands(
|
|
1080
|
+
pi: ExtensionAPI,
|
|
1081
|
+
statusController: PiUsereqStatusController,
|
|
1082
|
+
): void {
|
|
899
1083
|
PROMPT_NAMES.forEach((promptName) => {
|
|
900
1084
|
pi.registerCommand(`req-${promptName}`, {
|
|
901
1085
|
description: `Run pi-usereq prompt ${promptName}`,
|
|
@@ -903,6 +1087,10 @@ function registerPromptCommands(pi: ExtensionAPI): void {
|
|
|
903
1087
|
ensureBundledResourcesAccessible();
|
|
904
1088
|
const projectBase = getProjectBase(ctx.cwd);
|
|
905
1089
|
const config = loadProjectConfig(ctx.cwd);
|
|
1090
|
+
statusController.state.pendingPromptRequest = {
|
|
1091
|
+
promptName,
|
|
1092
|
+
promptArgs: args,
|
|
1093
|
+
};
|
|
906
1094
|
const content = renderPrompt(promptName, args, projectBase, config);
|
|
907
1095
|
await deliverPromptCommand(pi, content);
|
|
908
1096
|
},
|
|
@@ -922,17 +1110,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
922
1110
|
const gitPathSchema = Type.Object(
|
|
923
1111
|
{},
|
|
924
1112
|
{
|
|
925
|
-
description: "Input contract: no params. Output contract: JSON object with
|
|
1113
|
+
description: "Input contract: no params. Output contract: JSON object with result and execution. Result exposes path_value and path_present for the cwd-derived runtime git root.",
|
|
926
1114
|
},
|
|
927
1115
|
);
|
|
928
1116
|
pi.registerTool({
|
|
929
1117
|
name: "git-path",
|
|
930
1118
|
label: "git-path",
|
|
931
|
-
description: "Scope: current runtime path. Return a
|
|
1119
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes the resolved `git-path` value through direct-access fields without request echoes.",
|
|
932
1120
|
promptSnippet: "Return the structured runtime git-root payload for the current project.",
|
|
933
1121
|
promptGuidelines: [
|
|
934
1122
|
"Input contract: no params. Scope is the cwd-derived runtime path context.",
|
|
935
|
-
"Output contract:
|
|
1123
|
+
"Output contract: result + execution. Result exposes path_value and path_present.",
|
|
936
1124
|
"Behavior contract: git-path is derived at runtime from the current working directory and repository ancestry rules.",
|
|
937
1125
|
"Failure contract: configuration-loading failures surface through execution.code and execution.stderr_lines.",
|
|
938
1126
|
],
|
|
@@ -941,14 +1129,12 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
941
1129
|
ensureBundledResourcesAccessible();
|
|
942
1130
|
const projectBase = getProjectBase(process.cwd());
|
|
943
1131
|
const config = loadProjectConfig(process.cwd());
|
|
944
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
945
1132
|
const result = runGitPath(projectBase, config);
|
|
946
1133
|
const payload = buildPathQueryToolPayload(
|
|
947
1134
|
"git-path",
|
|
948
1135
|
process.cwd(),
|
|
949
1136
|
projectBase,
|
|
950
1137
|
result.stdout.trimEnd(),
|
|
951
|
-
runtimePaths,
|
|
952
1138
|
buildToolExecutionSection(result),
|
|
953
1139
|
);
|
|
954
1140
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -958,17 +1144,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
958
1144
|
const basePathSchema = Type.Object(
|
|
959
1145
|
{},
|
|
960
1146
|
{
|
|
961
|
-
description: "Input contract: no params. Output contract: JSON object with
|
|
1147
|
+
description: "Input contract: no params. Output contract: JSON object with result and execution. Result exposes path_value and path_present for the cwd-derived runtime base path.",
|
|
962
1148
|
},
|
|
963
1149
|
);
|
|
964
1150
|
pi.registerTool({
|
|
965
1151
|
name: "get-base-path",
|
|
966
1152
|
label: "get-base-path",
|
|
967
|
-
description: "Scope: current runtime path. Return a
|
|
1153
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes the resolved `base-path` value through direct-access fields without request echoes.",
|
|
968
1154
|
promptSnippet: "Return the structured runtime project-base payload.",
|
|
969
1155
|
promptGuidelines: [
|
|
970
1156
|
"Input contract: no params. Scope is the cwd-derived runtime path context.",
|
|
971
|
-
"Output contract:
|
|
1157
|
+
"Output contract: result + execution. Result exposes path_value and path_present.",
|
|
972
1158
|
"Behavior contract: base-path equals the current working directory used by the extension command or tool.",
|
|
973
1159
|
"Failure contract: configuration-loading failures surface through execution.code and execution.stderr_lines.",
|
|
974
1160
|
],
|
|
@@ -976,14 +1162,12 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
976
1162
|
async execute() {
|
|
977
1163
|
const projectBase = getProjectBase(process.cwd());
|
|
978
1164
|
const config = loadProjectConfig(process.cwd());
|
|
979
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
980
1165
|
const result = runGetBasePath(projectBase, config);
|
|
981
1166
|
const payload = buildPathQueryToolPayload(
|
|
982
1167
|
"get-base-path",
|
|
983
1168
|
process.cwd(),
|
|
984
1169
|
projectBase,
|
|
985
1170
|
result.stdout.trimEnd(),
|
|
986
|
-
runtimePaths,
|
|
987
1171
|
buildToolExecutionSection(result),
|
|
988
1172
|
);
|
|
989
1173
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -998,7 +1182,7 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
998
1182
|
),
|
|
999
1183
|
},
|
|
1000
1184
|
{
|
|
1001
|
-
description: "Input contract: files[]. Output contract: JSON object with
|
|
1185
|
+
description: "Input contract: files[]. Output contract: JSON object with summary, repository, files, and execution. File entries expose canonical paths, numeric line ranges, imports, symbols, structured Doxygen fields, standalone comments, and structured status facts. Missing or unsupported inputs become skipped entries. The tool fails when no source file can be analyzed.",
|
|
1002
1186
|
},
|
|
1003
1187
|
);
|
|
1004
1188
|
const multiFileSchema = Type.Object(
|
|
@@ -1009,7 +1193,7 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1009
1193
|
),
|
|
1010
1194
|
},
|
|
1011
1195
|
{
|
|
1012
|
-
description: "Input contract: files[]. Output contract: JSON object with
|
|
1196
|
+
description: "Input contract: files[]. Output contract: JSON object with summary, files, and execution. File entries expose canonical paths, detected language, configured checker modules, selection status, and error facts.",
|
|
1013
1197
|
},
|
|
1014
1198
|
);
|
|
1015
1199
|
const filesTokensSchema = Type.Object(
|
|
@@ -1020,19 +1204,19 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1020
1204
|
),
|
|
1021
1205
|
},
|
|
1022
1206
|
{
|
|
1023
|
-
description: "Input contract: files[]. Output contract: JSON object with
|
|
1207
|
+
description: "Input contract: files[]. Output contract: JSON object with summary, files, and execution. File entries expose direct-access facts, token metrics, and optional heading or Doxygen metadata. Missing or non-file inputs become skipped entries. The tool fails when no processable files remain.",
|
|
1024
1208
|
},
|
|
1025
1209
|
);
|
|
1026
1210
|
|
|
1027
1211
|
pi.registerTool({
|
|
1028
1212
|
name: "files-tokens",
|
|
1029
1213
|
label: "files-tokens",
|
|
1030
|
-
description: "Scope: explicit files. Return
|
|
1214
|
+
description: "Scope: explicit files. Return a token-optimized JSON payload with summary, files, and execution sections. File entries expose direct-access path facts, status, size metrics, and optional heading or Doxygen metadata.",
|
|
1031
1215
|
promptSnippet: "Return the structured token-analysis payload for caller-selected files.",
|
|
1032
1216
|
promptGuidelines: [
|
|
1033
1217
|
"Scope: explicit files selected by files[]; caller order is preserved; each item may be project-relative or absolute.",
|
|
1034
|
-
"Output contract:
|
|
1035
|
-
"Numeric contract: counts, sizes, shares, and line ranges remain in dedicated numeric fields;
|
|
1218
|
+
"Output contract: summary + files + execution. File entries expose canonical paths, absolute paths, existence, file status, line range, line count, byte count, character count, token count, shares, and optional primary-heading or Doxygen file metadata.",
|
|
1219
|
+
"Numeric contract: counts, sizes, shares, and line ranges remain in dedicated numeric fields; static request metadata and derived guidance are omitted from runtime responses.",
|
|
1036
1220
|
"Behavior contract: missing or non-file inputs become skipped entries; read failures become error entries; the tool fails only when no processable files remain.",
|
|
1037
1221
|
],
|
|
1038
1222
|
parameters: filesTokensSchema,
|
|
@@ -1051,11 +1235,11 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1051
1235
|
pi.registerTool({
|
|
1052
1236
|
name: "files-references",
|
|
1053
1237
|
label: "files-references",
|
|
1054
|
-
description: "Scope: explicit source files. Return
|
|
1238
|
+
description: "Scope: explicit source files. Return a token-optimized JSON payload with summary, repository, files, and execution sections. File entries expose canonical paths, numeric line ranges, imports, symbols, structured Doxygen fields, standalone comments, and structured status facts.",
|
|
1055
1239
|
promptSnippet: "Return the structured references payload for caller-selected source files.",
|
|
1056
1240
|
promptGuidelines: [
|
|
1057
1241
|
"Scope: explicit source files selected by files[]; caller order is preserved; each item may be project-relative or absolute.",
|
|
1058
|
-
"Output contract:
|
|
1242
|
+
"Output contract: summary + repository + files + execution. File entries expose canonical paths, absolute paths, file status, line counts, line ranges, imports, symbols, child relationships, standalone comments, and structured Doxygen metadata.",
|
|
1059
1243
|
"Numeric contract: line counts, line ranges, symbol counts, import counts, comment counts, and Doxygen counts remain in dedicated numeric fields; text is limited to residual comment or signature content that cannot be split safely.",
|
|
1060
1244
|
"Behavior contract: missing inputs, non-file inputs, and unsupported extensions become structured skipped entries; analysis failures become structured error entries; the tool fails only when no source file can be analyzed.",
|
|
1061
1245
|
],
|
|
@@ -1080,18 +1264,18 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1080
1264
|
enableLineNumbers: Type.Optional(Type.Boolean({ description: "When true, `compressed_source_text` and `compressed_lines[].display_text` include original source line-number prefixes" })),
|
|
1081
1265
|
},
|
|
1082
1266
|
{
|
|
1083
|
-
description: "Input contract: files[] plus optional enableLineNumbers. Output contract: JSON object with
|
|
1267
|
+
description: "Input contract: files[] plus optional enableLineNumbers. Output contract: JSON object with summary, repository, files, and execution. File entries expose path identifiers, source and compressed line metrics, structured compressed lines, symbols, structured Doxygen fields, and stable status facts. Missing, unsupported, or invalid inputs become structured skipped entries. The tool fails when no file is compressed.",
|
|
1084
1268
|
},
|
|
1085
1269
|
);
|
|
1086
1270
|
|
|
1087
1271
|
pi.registerTool({
|
|
1088
1272
|
name: "files-compress",
|
|
1089
1273
|
label: "files-compress",
|
|
1090
|
-
description: "Scope: explicit files. Return
|
|
1274
|
+
description: "Scope: explicit files. Return a token-optimized JSON payload with summary, repository, files, and execution sections. File entries expose canonical paths, source and compressed line metrics, structured compressed lines, symbols, structured Doxygen fields, and stable status facts.",
|
|
1091
1275
|
promptSnippet: "Return the structured compression payload for caller-selected source files.",
|
|
1092
1276
|
promptGuidelines: [
|
|
1093
1277
|
"Scope: explicit source files selected by files[]; caller order is preserved; each item may be project-relative or absolute.",
|
|
1094
|
-
"Output contract:
|
|
1278
|
+
"Output contract: summary + repository + files + execution. File entries expose canonical paths, absolute paths, line_number_mode, source line counts, source line ranges, compressed line counts, removed line counts, compressed_lines, compressed_source_text, symbols, and file_doxygen.",
|
|
1095
1279
|
"Line-number behavior: enableLineNumbers changes only rendered display strings; numeric source_line_number facts remain dedicated fields on compressed_lines for direct access.",
|
|
1096
1280
|
"Behavior contract: missing inputs, non-file inputs, and unsupported extensions become structured skipped entries; compression failures become structured error entries; symbol-analysis failures retain compressed output with symbol_analysis_status=error; the tool fails only when no file is compressed.",
|
|
1097
1281
|
],
|
|
@@ -1126,7 +1310,7 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1126
1310
|
pi.registerTool({
|
|
1127
1311
|
name: "files-find",
|
|
1128
1312
|
label: "files-find",
|
|
1129
|
-
description: "Scope: explicit source files. Return
|
|
1313
|
+
description: "Scope: explicit source files. Return a token-optimized JSON payload with summary, repository, files, and execution sections. File entries expose structured statuses and match records with typed location, symbol, stripped-code, and Doxygen facts.",
|
|
1130
1314
|
promptSnippet: "Return the structured construct-search payload for caller-selected source files.",
|
|
1131
1315
|
promptGuidelines: buildFindToolPromptGuidelines("explicit-files"),
|
|
1132
1316
|
parameters: filesFindSchema,
|
|
@@ -1147,24 +1331,24 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1147
1331
|
const referencesSchema = Type.Object(
|
|
1148
1332
|
{},
|
|
1149
1333
|
{
|
|
1150
|
-
description: "Input contract: no params. Scope is the configured src-dir list resolved from the current project configuration. Output contract: JSON object with
|
|
1334
|
+
description: "Input contract: no params. Scope is the configured src-dir list resolved from the current project configuration. Output contract: JSON object with summary, repository, files, and execution. Repository exposes the structured directory tree; file entries expose canonical paths, numeric line ranges, imports, symbols, structured Doxygen fields, and status facts. The tool fails when no configured source file can be analyzed.",
|
|
1151
1335
|
},
|
|
1152
1336
|
);
|
|
1153
1337
|
const tokensSchema = Type.Object(
|
|
1154
1338
|
{},
|
|
1155
1339
|
{
|
|
1156
|
-
description: "Input contract: no params. Scope is the configured docs-dir plus canonical docs REQUIREMENTS.md, WORKFLOW.md, and REFERENCES.md. Output contract: same
|
|
1340
|
+
description: "Input contract: no params. Scope is the configured docs-dir plus canonical docs REQUIREMENTS.md, WORKFLOW.md, and REFERENCES.md. Output contract: same token-optimized JSON shape as files-tokens. Missing canonical docs become skipped entries. The tool fails when no processable canonical docs remain.",
|
|
1157
1341
|
},
|
|
1158
1342
|
);
|
|
1159
1343
|
|
|
1160
1344
|
pi.registerTool({
|
|
1161
1345
|
name: "references",
|
|
1162
1346
|
label: "references",
|
|
1163
|
-
description: "Scope: configured project source directories. Return
|
|
1347
|
+
description: "Scope: configured project source directories. Return a token-optimized JSON payload with summary, repository, files, and execution sections. The repository section exposes the structured directory tree; file entries expose canonical paths, numeric line ranges, imports, symbols, structured Doxygen fields, standalone comments, and status facts.",
|
|
1164
1348
|
promptSnippet: "Return the structured project references payload from the configured source directories.",
|
|
1165
1349
|
promptGuidelines: [
|
|
1166
1350
|
"Scope: no params; resolve src-dir from the current project configuration and scan the configured source surface from the current working directory.",
|
|
1167
|
-
"Output contract:
|
|
1351
|
+
"Output contract: summary + repository + files + execution. Repository exposes source_directory_paths, file_canonical_paths, and directory_tree; file entries expose canonical paths, line counts, line ranges, imports, symbols, hierarchy, standalone comments, and structured Doxygen metadata.",
|
|
1168
1352
|
"Configuration contract: output changes with cwd-derived project config, src-dir values, and repository source discovery; the tool does not accept explicit file overrides.",
|
|
1169
1353
|
"Behavior contract: configured source files are analyzed in deterministic order, analysis failures become structured error entries, and the tool fails when no configured source file can be analyzed.",
|
|
1170
1354
|
],
|
|
@@ -1188,18 +1372,18 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1188
1372
|
enableLineNumbers: Type.Optional(Type.Boolean({ description: "When true, `compressed_source_text` and `compressed_lines[].display_text` include original source line-number prefixes" })),
|
|
1189
1373
|
},
|
|
1190
1374
|
{
|
|
1191
|
-
description: "Input contract: optional enableLineNumbers boolean. Scope is the configured src-dir list resolved from the current project configuration. Output contract: JSON object with
|
|
1375
|
+
description: "Input contract: optional enableLineNumbers boolean. Scope is the configured src-dir list resolved from the current project configuration. Output contract: JSON object with summary, repository, files, and execution. File entries expose path identifiers, source and compressed line metrics, structured compressed lines, symbols, structured Doxygen fields, and stable status facts. The tool fails when no configured source file is compressed.",
|
|
1192
1376
|
},
|
|
1193
1377
|
);
|
|
1194
1378
|
|
|
1195
1379
|
pi.registerTool({
|
|
1196
1380
|
name: "compress",
|
|
1197
1381
|
label: "compress",
|
|
1198
|
-
description: "Scope: configured project source directories. Return
|
|
1382
|
+
description: "Scope: configured project source directories. Return a token-optimized JSON payload with summary, repository, files, and execution sections. File entries expose canonical paths, source and compressed line metrics, structured compressed lines, symbols, structured Doxygen fields, and stable status facts.",
|
|
1199
1383
|
promptSnippet: "Return the structured project compression payload from the configured source directories.",
|
|
1200
1384
|
promptGuidelines: [
|
|
1201
1385
|
"Scope: resolve src-dir from the current project configuration and scan the configured source surface from the current working directory.",
|
|
1202
|
-
"Output contract:
|
|
1386
|
+
"Output contract: summary + repository + files + execution. Repository exposes source_directory_paths and file_canonical_paths; file entries expose line_number_mode, source line counts, source line ranges, compressed line counts, removed line counts, compressed_lines, compressed_source_text, symbols, and file_doxygen.",
|
|
1203
1387
|
"Configuration contract: output changes with cwd-derived project config, src-dir values, and repository source discovery; the tool does not accept explicit file overrides.",
|
|
1204
1388
|
"Behavior contract: configured source files are processed in deterministic order, compression failures become structured error entries, symbol-analysis failures retain compressed output with symbol_analysis_status=error, and the tool fails only when no configured source file is compressed.",
|
|
1205
1389
|
],
|
|
@@ -1234,7 +1418,7 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1234
1418
|
pi.registerTool({
|
|
1235
1419
|
name: "find",
|
|
1236
1420
|
label: "find",
|
|
1237
|
-
description: "Scope: configured project source directories. Return
|
|
1421
|
+
description: "Scope: configured project source directories. Return a token-optimized JSON payload with summary, repository, files, and execution sections. File entries expose structured statuses and match records with typed location, symbol, stripped-code, and Doxygen facts.",
|
|
1238
1422
|
promptSnippet: "Return the structured construct-search payload from the configured source directories.",
|
|
1239
1423
|
promptGuidelines: buildFindToolPromptGuidelines("configured-source-directories"),
|
|
1240
1424
|
parameters: findSchema,
|
|
@@ -1259,12 +1443,12 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1259
1443
|
pi.registerTool({
|
|
1260
1444
|
name: "tokens",
|
|
1261
1445
|
label: "tokens",
|
|
1262
|
-
description: "Scope: canonical docs from the configured docs-dir. Return the same
|
|
1446
|
+
description: "Scope: canonical docs from the configured docs-dir. Return the same token-optimized JSON contract as files-tokens, omitting canonical-doc request echoes from runtime responses.",
|
|
1263
1447
|
promptSnippet: "Return the structured token-analysis payload for canonical documentation files.",
|
|
1264
1448
|
promptGuidelines: [
|
|
1265
1449
|
"Scope: no params; resolve docs-dir from project config; target canonical docs REQUIREMENTS.md, WORKFLOW.md, and REFERENCES.md.",
|
|
1266
|
-
"Output contract:
|
|
1267
|
-
"Numeric contract: counts, sizes, shares, and line ranges remain in dedicated numeric fields; guidance
|
|
1450
|
+
"Output contract: summary + files + execution. Static docs-dir and canonical-doc selection facts remain documented in registration metadata; file entries expose direct-access path facts, line ranges, sizes, token metrics, and optional metadata.",
|
|
1451
|
+
"Numeric contract: counts, sizes, shares, and line ranges remain in dedicated numeric fields; derived guidance is omitted from runtime responses to reduce token cost.",
|
|
1268
1452
|
"Behavior contract: missing canonical docs become skipped entries; read failures become error entries; the tool fails only when no processable canonical docs remain.",
|
|
1269
1453
|
],
|
|
1270
1454
|
parameters: tokensSchema,
|
|
@@ -1289,11 +1473,11 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1289
1473
|
pi.registerTool({
|
|
1290
1474
|
name: "files-static-check",
|
|
1291
1475
|
label: "files-static-check",
|
|
1292
|
-
description: "Scope: explicit files. Return a
|
|
1476
|
+
description: "Scope: explicit files. Return a token-optimized JSON payload with summary, files, and execution sections. File entries expose canonical paths, detected language, configured checker modules, selection status, and stable error facts.",
|
|
1293
1477
|
promptSnippet: "Return the structured explicit-file static-check payload for the current project configuration.",
|
|
1294
1478
|
promptGuidelines: [
|
|
1295
1479
|
"Input contract: files[]. Scope is explicit caller-selected files resolved from the current working directory.",
|
|
1296
|
-
"Output contract:
|
|
1480
|
+
"Output contract: summary + files + execution. File entries expose canonical_path, language_name, configured_checker_modules, status, and error_message.",
|
|
1297
1481
|
"Configuration contract: checker selection is derived from the cwd-resolved static-check configuration and file extensions only.",
|
|
1298
1482
|
"Failure contract: execution.code mirrors aggregated checker failures; execution.stdout_lines and execution.stderr_lines preserve residual checker diagnostics.",
|
|
1299
1483
|
],
|
|
@@ -1301,7 +1485,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1301
1485
|
async execute(_toolCallId, params) {
|
|
1302
1486
|
const projectBase = getProjectBase(process.cwd());
|
|
1303
1487
|
const config = loadProjectConfig(process.cwd());
|
|
1304
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1305
1488
|
const staticCheckConfig = config["static-check"] ?? {};
|
|
1306
1489
|
const result = runFilesStaticCheck(params.files, projectBase, config);
|
|
1307
1490
|
const payload = buildStaticCheckToolPayload(
|
|
@@ -1312,7 +1495,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1312
1495
|
[],
|
|
1313
1496
|
[],
|
|
1314
1497
|
staticCheckConfig,
|
|
1315
|
-
runtimePaths,
|
|
1316
1498
|
buildToolExecutionSection(result),
|
|
1317
1499
|
);
|
|
1318
1500
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -1322,17 +1504,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1322
1504
|
const staticCheckSchema = Type.Object(
|
|
1323
1505
|
{},
|
|
1324
1506
|
{
|
|
1325
|
-
description: "Input contract: no params. Scope is the configured src-dir plus tests-dir selection after fixture exclusion. Output contract: JSON object with
|
|
1507
|
+
description: "Input contract: no params. Scope is the configured src-dir plus tests-dir selection after fixture exclusion. Output contract: JSON object with summary, files, and execution.",
|
|
1326
1508
|
},
|
|
1327
1509
|
);
|
|
1328
1510
|
pi.registerTool({
|
|
1329
1511
|
name: "static-check",
|
|
1330
1512
|
label: "static-check",
|
|
1331
|
-
description: "Scope: configured source and test directories. Return a
|
|
1513
|
+
description: "Scope: configured source and test directories. Return a token-optimized JSON payload with summary, files, and execution sections. File entries expose selected-path facts, checker coverage, selection status, and residual diagnostics metadata.",
|
|
1332
1514
|
promptSnippet: "Return the structured project static-check payload for the current configuration.",
|
|
1333
1515
|
promptGuidelines: [
|
|
1334
1516
|
"Input contract: no params. Scope is src-dir plus tests-dir from the cwd-derived project configuration.",
|
|
1335
|
-
"Output contract:
|
|
1517
|
+
"Output contract: summary + files + execution. Selection-directory rules remain documented in registration metadata; file entries expose configured_checker_modules and status.",
|
|
1336
1518
|
"Selection contract: tests/fixtures and <tests-dir>/fixtures are excluded before checker dispatch.",
|
|
1337
1519
|
"Failure contract: execution.code mirrors aggregated checker failures or selection failures; execution.stderr_lines preserve residual diagnostics.",
|
|
1338
1520
|
],
|
|
@@ -1340,7 +1522,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1340
1522
|
async execute() {
|
|
1341
1523
|
const projectBase = getProjectBase(process.cwd());
|
|
1342
1524
|
const config = loadProjectConfig(process.cwd());
|
|
1343
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1344
1525
|
const staticCheckConfig = config["static-check"] ?? {};
|
|
1345
1526
|
const selectionDirectoryPaths = [...config["src-dir"], config["tests-dir"]];
|
|
1346
1527
|
const testsDirRel = makeRelativeIfContainsProject(config["tests-dir"], projectBase)
|
|
@@ -1368,7 +1549,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1368
1549
|
selectionDirectoryPaths,
|
|
1369
1550
|
excludedDirectoryPaths,
|
|
1370
1551
|
staticCheckConfig,
|
|
1371
|
-
runtimePaths,
|
|
1372
1552
|
execution,
|
|
1373
1553
|
);
|
|
1374
1554
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -1378,17 +1558,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1378
1558
|
const gitCheckSchema = Type.Object(
|
|
1379
1559
|
{},
|
|
1380
1560
|
{
|
|
1381
|
-
description: "Input contract: no params. Output contract: JSON object with
|
|
1561
|
+
description: "Input contract: no params. Output contract: JSON object with result and execution. Result exposes git-path presence plus aggregate repository status fields.",
|
|
1382
1562
|
},
|
|
1383
1563
|
);
|
|
1384
1564
|
pi.registerTool({
|
|
1385
1565
|
name: "git-check",
|
|
1386
1566
|
label: "git-check",
|
|
1387
|
-
description: "Scope: current runtime path. Return a
|
|
1567
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes repository validation status through direct fields without request echoes.",
|
|
1388
1568
|
promptSnippet: "Return the structured git-validation payload for the runtime repository.",
|
|
1389
1569
|
promptGuidelines: [
|
|
1390
1570
|
"Input contract: no params. Scope is the cwd-derived runtime path context.",
|
|
1391
|
-
"Output contract:
|
|
1571
|
+
"Output contract: result + execution. Result exposes git_path_present and aggregate status.",
|
|
1392
1572
|
"Behavior contract: the tool checks work-tree membership, porcelain cleanliness, and symbolic-or-detached HEAD validity.",
|
|
1393
1573
|
"Failure contract: execution.code and execution.stderr_lines surface git-path or repository-state errors.",
|
|
1394
1574
|
],
|
|
@@ -1396,14 +1576,13 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1396
1576
|
async execute() {
|
|
1397
1577
|
const projectBase = getProjectBase(process.cwd());
|
|
1398
1578
|
const config = loadProjectConfig(process.cwd());
|
|
1399
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1400
1579
|
let execution;
|
|
1401
1580
|
try {
|
|
1402
1581
|
execution = buildToolExecutionSection(runGitCheck(projectBase, config));
|
|
1403
1582
|
} catch (error) {
|
|
1404
1583
|
execution = buildToolExecutionSection(normalizeToolFailure(error));
|
|
1405
1584
|
}
|
|
1406
|
-
const payload = buildGitCheckToolPayload(projectBase, resolveRuntimeGitPath(projectBase),
|
|
1585
|
+
const payload = buildGitCheckToolPayload(projectBase, resolveRuntimeGitPath(projectBase), execution);
|
|
1407
1586
|
return buildStructuredToolExecuteResult(payload);
|
|
1408
1587
|
},
|
|
1409
1588
|
});
|
|
@@ -1411,17 +1590,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1411
1590
|
const docsCheckSchema = Type.Object(
|
|
1412
1591
|
{},
|
|
1413
1592
|
{
|
|
1414
|
-
description: "Input contract: no params. Output contract: JSON object with
|
|
1593
|
+
description: "Input contract: no params. Output contract: JSON object with summary, files, and execution. File entries expose canonical paths, prompt_command remediation, and presence status for canonical docs.",
|
|
1415
1594
|
},
|
|
1416
1595
|
);
|
|
1417
1596
|
pi.registerTool({
|
|
1418
1597
|
name: "docs-check",
|
|
1419
1598
|
label: "docs-check",
|
|
1420
|
-
description: "Scope: canonical docs. Return a
|
|
1599
|
+
description: "Scope: canonical docs. Return a token-optimized JSON payload with summary, files, and execution sections. File entries expose remediation prompt commands and direct presence facts for REQUIREMENTS.md, WORKFLOW.md, and REFERENCES.md.",
|
|
1421
1600
|
promptSnippet: "Return the structured canonical-document validation payload.",
|
|
1422
1601
|
promptGuidelines: [
|
|
1423
1602
|
"Input contract: no params. Scope is docs-dir from the cwd-derived project configuration.",
|
|
1424
|
-
"Output contract:
|
|
1603
|
+
"Output contract: summary + files + execution. File entries expose file_name, canonical_path, prompt_command, and status.",
|
|
1425
1604
|
"Specialization trigger: remediation differs per missing canonical file through prompt_command.",
|
|
1426
1605
|
"Failure contract: execution.code is non-zero when any canonical document is missing; execution.stderr_lines enumerate missing files.",
|
|
1427
1606
|
],
|
|
@@ -1429,8 +1608,7 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1429
1608
|
async execute() {
|
|
1430
1609
|
const projectBase = getProjectBase(process.cwd());
|
|
1431
1610
|
const config = loadProjectConfig(process.cwd());
|
|
1432
|
-
const
|
|
1433
|
-
const payload = buildDocsCheckToolPayload(projectBase, config["docs-dir"], runtimePaths);
|
|
1611
|
+
const payload = buildDocsCheckToolPayload(projectBase, config["docs-dir"]);
|
|
1434
1612
|
return buildStructuredToolExecuteResult(payload);
|
|
1435
1613
|
},
|
|
1436
1614
|
});
|
|
@@ -1438,17 +1616,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1438
1616
|
const gitWtNameSchema = Type.Object(
|
|
1439
1617
|
{},
|
|
1440
1618
|
{
|
|
1441
|
-
description: "Input contract: no params. Output contract: JSON object with
|
|
1619
|
+
description: "Input contract: no params. Output contract: JSON object with result and execution. Result exposes worktree_name when generation succeeds.",
|
|
1442
1620
|
},
|
|
1443
1621
|
);
|
|
1444
1622
|
pi.registerTool({
|
|
1445
1623
|
name: "git-wt-name",
|
|
1446
1624
|
label: "git-wt-name",
|
|
1447
|
-
description: "Scope: current runtime path. Return a
|
|
1625
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes the generated worktree name while static naming rules remain in registration metadata.",
|
|
1448
1626
|
promptSnippet: "Return the structured worktree-name generation payload.",
|
|
1449
1627
|
promptGuidelines: [
|
|
1450
1628
|
"Input contract: no params. Scope is the cwd-derived runtime path context.",
|
|
1451
|
-
"Output contract:
|
|
1629
|
+
"Output contract: result + execution. Result exposes worktree_name.",
|
|
1452
1630
|
"Behavior contract: generation follows useReq-<project>-<sanitized-branch>-<YYYYMMDDHHMMSS>.",
|
|
1453
1631
|
"Failure contract: execution.code and execution.stderr_lines surface git-path or branch-resolution errors.",
|
|
1454
1632
|
],
|
|
@@ -1456,14 +1634,13 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1456
1634
|
async execute() {
|
|
1457
1635
|
const projectBase = getProjectBase(process.cwd());
|
|
1458
1636
|
const config = loadProjectConfig(process.cwd());
|
|
1459
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1460
1637
|
let execution;
|
|
1461
1638
|
try {
|
|
1462
1639
|
execution = buildToolExecutionSection(runGitWtName(projectBase, config));
|
|
1463
1640
|
} catch (error) {
|
|
1464
1641
|
execution = buildToolExecutionSection(normalizeToolFailure(error));
|
|
1465
1642
|
}
|
|
1466
|
-
const payload = buildWorktreeNameToolPayload(projectBase, resolveRuntimeGitPath(projectBase),
|
|
1643
|
+
const payload = buildWorktreeNameToolPayload(projectBase, resolveRuntimeGitPath(projectBase), execution);
|
|
1467
1644
|
return buildStructuredToolExecuteResult(payload);
|
|
1468
1645
|
},
|
|
1469
1646
|
});
|
|
@@ -1473,17 +1650,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1473
1650
|
wtName: Type.String({ description: "Exact target worktree name and branch name" }),
|
|
1474
1651
|
},
|
|
1475
1652
|
{
|
|
1476
|
-
description: "Input contract: wtName. Output contract: JSON object with
|
|
1653
|
+
description: "Input contract: wtName. Output contract: JSON object with result and execution. Result exposes worktree_name and derived worktree_path.",
|
|
1477
1654
|
},
|
|
1478
1655
|
);
|
|
1479
1656
|
pi.registerTool({
|
|
1480
1657
|
name: "git-wt-create",
|
|
1481
1658
|
label: "git-wt-create",
|
|
1482
|
-
description: "Scope: current runtime path. Return a
|
|
1659
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes the exact worktree name and derived path without static operation echoes.",
|
|
1483
1660
|
promptSnippet: "Return the structured worktree-creation payload for the requested name.",
|
|
1484
1661
|
promptGuidelines: [
|
|
1485
1662
|
"Input contract: wtName is required and must match the exact worktree/branch name to create.",
|
|
1486
|
-
"Output contract:
|
|
1663
|
+
"Output contract: result + execution. Result exposes worktree_name and worktree_path.",
|
|
1487
1664
|
"Specialization trigger: worktree_path depends on the runtime git root parent directory.",
|
|
1488
1665
|
"Failure contract: execution.code and execution.stderr_lines surface invalid-name, git, or finalization errors.",
|
|
1489
1666
|
],
|
|
@@ -1491,7 +1668,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1491
1668
|
async execute(_toolCallId, params) {
|
|
1492
1669
|
const projectBase = getProjectBase(process.cwd());
|
|
1493
1670
|
const config = loadProjectConfig(process.cwd());
|
|
1494
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1495
1671
|
let execution;
|
|
1496
1672
|
try {
|
|
1497
1673
|
execution = buildToolExecutionSection(runGitWtCreate(projectBase, params.wtName, config));
|
|
@@ -1503,7 +1679,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1503
1679
|
projectBase,
|
|
1504
1680
|
resolveRuntimeGitPath(projectBase),
|
|
1505
1681
|
params.wtName,
|
|
1506
|
-
runtimePaths,
|
|
1507
1682
|
execution,
|
|
1508
1683
|
);
|
|
1509
1684
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -1515,17 +1690,17 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1515
1690
|
wtName: Type.String({ description: "Exact target worktree name and branch name" }),
|
|
1516
1691
|
},
|
|
1517
1692
|
{
|
|
1518
|
-
description: "Input contract: wtName. Output contract: JSON object with
|
|
1693
|
+
description: "Input contract: wtName. Output contract: JSON object with result and execution. Result exposes worktree_name and derived worktree_path.",
|
|
1519
1694
|
},
|
|
1520
1695
|
);
|
|
1521
1696
|
pi.registerTool({
|
|
1522
1697
|
name: "git-wt-delete",
|
|
1523
1698
|
label: "git-wt-delete",
|
|
1524
|
-
description: "Scope: current runtime path. Return a
|
|
1699
|
+
description: "Scope: current runtime path. Return a token-optimized JSON payload with result and execution sections. Result exposes the exact worktree name and derived path without static operation echoes.",
|
|
1525
1700
|
promptSnippet: "Return the structured worktree-deletion payload for the requested name.",
|
|
1526
1701
|
promptGuidelines: [
|
|
1527
1702
|
"Input contract: wtName is required and must match the exact worktree/branch name to delete.",
|
|
1528
|
-
"Output contract:
|
|
1703
|
+
"Output contract: result + execution. Result exposes worktree_name and worktree_path.",
|
|
1529
1704
|
"Specialization trigger: worktree_path depends on the runtime git root parent directory.",
|
|
1530
1705
|
"Failure contract: execution.code and execution.stderr_lines surface missing-target or deletion errors.",
|
|
1531
1706
|
],
|
|
@@ -1533,7 +1708,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1533
1708
|
async execute(_toolCallId, params) {
|
|
1534
1709
|
const projectBase = getProjectBase(process.cwd());
|
|
1535
1710
|
const config = loadProjectConfig(process.cwd());
|
|
1536
|
-
const runtimePaths = buildSharedRuntimePathFacts(process.cwd(), config);
|
|
1537
1711
|
let execution;
|
|
1538
1712
|
try {
|
|
1539
1713
|
execution = buildToolExecutionSection(runGitWtDelete(projectBase, params.wtName, config));
|
|
@@ -1545,7 +1719,6 @@ function registerAgentTools(pi: ExtensionAPI): void {
|
|
|
1545
1719
|
projectBase,
|
|
1546
1720
|
resolveRuntimeGitPath(projectBase),
|
|
1547
1721
|
params.wtName,
|
|
1548
|
-
runtimePaths,
|
|
1549
1722
|
execution,
|
|
1550
1723
|
);
|
|
1551
1724
|
return buildStructuredToolExecuteResult(payload);
|
|
@@ -1721,7 +1894,7 @@ function formatStaticCheckLanguagesSummary(config: UseReqConfig): string {
|
|
|
1721
1894
|
|
|
1722
1895
|
/**
|
|
1723
1896
|
* @brief Renders the static-check configuration reference view.
|
|
1724
|
-
* @details Produces a markdown-like summary containing configured entries, supported languages,
|
|
1897
|
+
* @details Produces a markdown-like summary containing configured entries, supported languages, the Command-only user module surface, and canonical example specifications. Runtime is O(l log l). No side effects occur.
|
|
1725
1898
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
1726
1899
|
* @return {string} Reference text for the editor view.
|
|
1727
1900
|
*/
|
|
@@ -1744,16 +1917,23 @@ function renderStaticCheckReference(config: UseReqConfig): string {
|
|
|
1744
1917
|
for (const { language, extensions } of getSupportedStaticCheckLanguageSupport()) {
|
|
1745
1918
|
lines.push(`- ${language}: ${extensions.join(", ")}`);
|
|
1746
1919
|
}
|
|
1747
|
-
lines.push(
|
|
1920
|
+
lines.push(
|
|
1921
|
+
"",
|
|
1922
|
+
`Supported modules: ${STATIC_CHECK_MODULES.join(", ")}`,
|
|
1923
|
+
"",
|
|
1924
|
+
"Examples:",
|
|
1925
|
+
"- Python=Command,mypy,--strict",
|
|
1926
|
+
"- TypeScript=Command,eslint,--max-warnings,0",
|
|
1927
|
+
);
|
|
1748
1928
|
return `${lines.join("\n")}\n`;
|
|
1749
1929
|
}
|
|
1750
1930
|
|
|
1751
1931
|
/**
|
|
1752
1932
|
* @brief Builds the shared settings-menu choices for static-check management.
|
|
1753
|
-
* @details Serializes static-check actions into right-valued menu rows consumed by the shared settings-menu renderer. Runtime is O(1). No external state is mutated.
|
|
1933
|
+
* @details Serializes Command-oriented static-check actions into right-valued menu rows consumed by the shared settings-menu renderer while omitting user-facing module selection. Runtime is O(1). No external state is mutated.
|
|
1754
1934
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
1755
1935
|
* @return {PiUsereqSettingsMenuChoice[]} Ordered static-check menu choices.
|
|
1756
|
-
* @satisfies REQ-008, REQ-151, REQ-152, REQ-153, REQ-154
|
|
1936
|
+
* @satisfies REQ-008, REQ-160, REQ-161, REQ-151, REQ-152, REQ-153, REQ-154
|
|
1757
1937
|
*/
|
|
1758
1938
|
function buildStaticCheckMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuChoice[] {
|
|
1759
1939
|
const supportedLanguageCount = getSupportedStaticCheckLanguageSupport().length;
|
|
@@ -1763,13 +1943,13 @@ function buildStaticCheckMenuChoices(config: UseReqConfig): PiUsereqSettingsMenu
|
|
|
1763
1943
|
id: "add-entry-supported-language",
|
|
1764
1944
|
label: "Add entry for supported language",
|
|
1765
1945
|
value: `${supportedLanguageCount} languages`,
|
|
1766
|
-
description: "Select a supported language, then
|
|
1946
|
+
description: "Select a supported language, then configure the Command static-check executable.",
|
|
1767
1947
|
},
|
|
1768
1948
|
{
|
|
1769
1949
|
id: "add-entry-raw-spec",
|
|
1770
1950
|
label: "Add entry from LANG=MODULE[,CMD[,PARAM...]]",
|
|
1771
1951
|
value: "raw spec",
|
|
1772
|
-
description: "Enter one raw static-check specification string in canonical CLI format.",
|
|
1952
|
+
description: "Enter one raw Command-based static-check specification string in canonical CLI format.",
|
|
1773
1953
|
},
|
|
1774
1954
|
{
|
|
1775
1955
|
id: "remove-language-entry",
|
|
@@ -1794,7 +1974,7 @@ function buildStaticCheckMenuChoices(config: UseReqConfig): PiUsereqSettingsMenu
|
|
|
1794
1974
|
|
|
1795
1975
|
/**
|
|
1796
1976
|
* @brief Builds the shared settings-menu choices for supported static-check languages.
|
|
1797
|
-
* @details Exposes every supported language as one row whose right-side value reports extensions plus the current configured checker count. Runtime is O(l log l). No external state is mutated.
|
|
1977
|
+
* @details Exposes every supported language as one row whose right-side value reports extensions plus the current configured checker count for Command-oriented configuration flows. Runtime is O(l log l). No external state is mutated.
|
|
1798
1978
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
1799
1979
|
* @return {PiUsereqSettingsMenuChoice[]} Ordered language-choice vector.
|
|
1800
1980
|
*/
|
|
@@ -1807,7 +1987,7 @@ function buildSupportedStaticCheckLanguageChoices(config: UseReqConfig): PiUsere
|
|
|
1807
1987
|
id: language,
|
|
1808
1988
|
label: language,
|
|
1809
1989
|
value: `${extensions.join(", ")} • ${configuredCount} ${suffix}`,
|
|
1810
|
-
description: `Configure static-check
|
|
1990
|
+
description: `Configure the Command static-check entry for ${language}. Supported extensions: ${extensions.join(", ")}.`,
|
|
1811
1991
|
};
|
|
1812
1992
|
}),
|
|
1813
1993
|
{
|
|
@@ -1819,31 +1999,6 @@ function buildSupportedStaticCheckLanguageChoices(config: UseReqConfig): PiUsere
|
|
|
1819
1999
|
];
|
|
1820
2000
|
}
|
|
1821
2001
|
|
|
1822
|
-
/**
|
|
1823
|
-
* @brief Builds the shared settings-menu choices for static-check modules.
|
|
1824
|
-
* @details Exposes every supported static-check module as one selectable row with a concise execution description. Runtime is O(m) in module count. No external state is mutated.
|
|
1825
|
-
* @param[in] language {string} Canonical selected language.
|
|
1826
|
-
* @return {PiUsereqSettingsMenuChoice[]} Ordered module-choice vector.
|
|
1827
|
-
*/
|
|
1828
|
-
function buildStaticCheckModuleChoices(language: string): PiUsereqSettingsMenuChoice[] {
|
|
1829
|
-
return [
|
|
1830
|
-
...STATIC_CHECK_MODULES.map((moduleName) => ({
|
|
1831
|
-
id: moduleName,
|
|
1832
|
-
label: moduleName,
|
|
1833
|
-
value: language,
|
|
1834
|
-
description: moduleName === "Command"
|
|
1835
|
-
? `Run one explicit external command against ${language} files.`
|
|
1836
|
-
: `Run the built-in ${moduleName} checker for ${language} files.`,
|
|
1837
|
-
})),
|
|
1838
|
-
{
|
|
1839
|
-
id: "back",
|
|
1840
|
-
label: "Back",
|
|
1841
|
-
value: "",
|
|
1842
|
-
description: "Return to language selection.",
|
|
1843
|
-
},
|
|
1844
|
-
];
|
|
1845
|
-
}
|
|
1846
|
-
|
|
1847
2002
|
/**
|
|
1848
2003
|
* @brief Builds the shared settings-menu choices for configured static-check languages.
|
|
1849
2004
|
* @details Exposes only languages that currently have at least one configured checker so removal remains deterministic. Runtime is O(l log l). No external state is mutated.
|
|
@@ -1871,11 +2026,11 @@ function buildConfiguredStaticCheckLanguageChoices(config: UseReqConfig): PiUser
|
|
|
1871
2026
|
|
|
1872
2027
|
/**
|
|
1873
2028
|
* @brief Runs the interactive static-check configuration menu.
|
|
1874
|
-
* @details Lets the user inspect support, add entries by guided prompts or raw spec strings, and remove configured language entries through the shared settings-menu renderer until the user exits. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
2029
|
+
* @details Lets the user inspect support, add Command entries by guided prompts or raw spec strings, and remove configured language entries through the shared settings-menu renderer until the user exits. Runtime depends on user interaction count. Side effects include UI updates and config mutation.
|
|
1875
2030
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
1876
2031
|
* @param[in,out] config {UseReqConfig} Mutable configuration object.
|
|
1877
2032
|
* @return {Promise<void>} Promise resolved when the menu closes.
|
|
1878
|
-
* @satisfies REQ-008, REQ-151, REQ-152, REQ-153, REQ-154
|
|
2033
|
+
* @satisfies REQ-008, REQ-160, REQ-161, REQ-151, REQ-152, REQ-153, REQ-154
|
|
1879
2034
|
*/
|
|
1880
2035
|
async function configureStaticCheckMenu(ctx: ExtensionCommandContext, config: UseReqConfig): Promise<void> {
|
|
1881
2036
|
while (true) {
|
|
@@ -1895,23 +2050,16 @@ async function configureStaticCheckMenu(ctx: ExtensionCommandContext, config: Us
|
|
|
1895
2050
|
if (!selectedLanguage || selectedLanguage === "back") {
|
|
1896
2051
|
continue;
|
|
1897
2052
|
}
|
|
1898
|
-
const moduleName = await showPiUsereqSettingsMenu(ctx, `static-check for ${selectedLanguage}`, buildStaticCheckModuleChoices(selectedLanguage));
|
|
1899
|
-
if (!moduleName || moduleName === "back") {
|
|
1900
|
-
continue;
|
|
1901
|
-
}
|
|
1902
2053
|
|
|
1903
|
-
const
|
|
1904
|
-
if (
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
ctx.ui.notify(`Command executable is required for ${selectedLanguage}`, "error");
|
|
1908
|
-
continue;
|
|
1909
|
-
}
|
|
1910
|
-
entry.cmd = cmd.trim();
|
|
2054
|
+
const cmd = await ctx.ui.input(`Command executable for ${selectedLanguage}`, "");
|
|
2055
|
+
if (!cmd?.trim()) {
|
|
2056
|
+
ctx.ui.notify(`Command executable is required for ${selectedLanguage}`, "error");
|
|
2057
|
+
continue;
|
|
1911
2058
|
}
|
|
1912
2059
|
|
|
2060
|
+
const entry: StaticCheckEntry = { module: "Command", cmd: cmd.trim() };
|
|
1913
2061
|
const paramsInput = await ctx.ui.input(
|
|
1914
|
-
`Additional parameters for
|
|
2062
|
+
`Additional parameters for Command on ${selectedLanguage} (optional, shell-style)`,
|
|
1915
2063
|
"",
|
|
1916
2064
|
);
|
|
1917
2065
|
const params = paramsInput?.trim() ? shellSplit(paramsInput.trim()) : [];
|
|
@@ -1926,7 +2074,7 @@ async function configureStaticCheckMenu(ctx: ExtensionCommandContext, config: Us
|
|
|
1926
2074
|
}
|
|
1927
2075
|
|
|
1928
2076
|
if (staticChoice === "add-entry-raw-spec") {
|
|
1929
|
-
const spec = await ctx.ui.input("Static-check spec", "Python=
|
|
2077
|
+
const spec = await ctx.ui.input("Static-check spec", "Python=Command,true");
|
|
1930
2078
|
if (!spec?.trim()) {
|
|
1931
2079
|
continue;
|
|
1932
2080
|
}
|
|
@@ -1954,12 +2102,16 @@ async function configureStaticCheckMenu(ctx: ExtensionCommandContext, config: Us
|
|
|
1954
2102
|
|
|
1955
2103
|
/**
|
|
1956
2104
|
* @brief Builds the shared settings-menu choices for the top-level pi-usereq configuration UI.
|
|
1957
|
-
* @details Serializes primary configuration actions into right-valued menu rows consumed by the shared settings-menu renderer
|
|
2105
|
+
* @details Serializes primary configuration actions into right-valued menu rows consumed by the shared settings-menu renderer, including the display-only config path beside `show-config`. Runtime is O(s) in source-directory count. No external state is mutated.
|
|
2106
|
+
* @param[in] cwd {string} Current working directory.
|
|
1958
2107
|
* @param[in] config {UseReqConfig} Effective project configuration.
|
|
1959
2108
|
* @return {PiUsereqSettingsMenuChoice[]} Ordered top-level menu choices.
|
|
1960
|
-
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152
|
|
2109
|
+
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-162
|
|
1961
2110
|
*/
|
|
1962
|
-
function buildPiUsereqMenuChoices(
|
|
2111
|
+
function buildPiUsereqMenuChoices(
|
|
2112
|
+
cwd: string,
|
|
2113
|
+
config: UseReqConfig,
|
|
2114
|
+
): PiUsereqSettingsMenuChoice[] {
|
|
1963
2115
|
return [
|
|
1964
2116
|
{
|
|
1965
2117
|
id: "docs-dir",
|
|
@@ -1995,7 +2147,14 @@ function buildPiUsereqMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuCho
|
|
|
1995
2147
|
id: "notifications",
|
|
1996
2148
|
label: "notifications",
|
|
1997
2149
|
value: `beep:${formatPiNotifyBeepStatus(config)} • sound:${config["notify-sound"]}`,
|
|
1998
|
-
description: "Manage terminal beep flags, selected notify command, hotkey bind,
|
|
2150
|
+
description: "Manage terminal beep flags, selected notify command, hotkey bind, per-level notify commands, and the nested Pushover submenu.",
|
|
2151
|
+
},
|
|
2152
|
+
{
|
|
2153
|
+
id: "show-config",
|
|
2154
|
+
label: "show-config",
|
|
2155
|
+
value: formatProjectConfigPathForMenu(cwd),
|
|
2156
|
+
valueTone: "dim",
|
|
2157
|
+
description: "Write the current project configuration JSON into the editor without saving additional changes.",
|
|
1999
2158
|
},
|
|
2000
2159
|
{
|
|
2001
2160
|
id: "reset-defaults",
|
|
@@ -2003,12 +2162,6 @@ function buildPiUsereqMenuChoices(config: UseReqConfig): PiUsereqSettingsMenuCho
|
|
|
2003
2162
|
value: "",
|
|
2004
2163
|
description: "Restore the default pi-usereq configuration for the current project base.",
|
|
2005
2164
|
},
|
|
2006
|
-
{
|
|
2007
|
-
id: "show-config",
|
|
2008
|
-
label: "show-config",
|
|
2009
|
-
value: "",
|
|
2010
|
-
description: "Write the current project configuration JSON into the editor without saving additional changes.",
|
|
2011
|
-
},
|
|
2012
2165
|
{
|
|
2013
2166
|
id: "save-and-close",
|
|
2014
2167
|
label: "Save and close",
|
|
@@ -2074,12 +2227,12 @@ function buildSrcDirRemovalChoices(config: UseReqConfig): PiUsereqSettingsMenuCh
|
|
|
2074
2227
|
|
|
2075
2228
|
/**
|
|
2076
2229
|
* @brief Runs the top-level pi-usereq configuration menu.
|
|
2077
|
-
* @details Loads project config, exposes docs/test/source/static-check/startup-tool/notification actions through the shared settings-menu renderer, persists changes on exit, and refreshes the single-line status bar. Runtime depends on user interaction count. Side effects include UI updates, config writes,
|
|
2230
|
+
* @details Loads project config, exposes docs/test/source/static-check/startup-tool/notification actions through the shared settings-menu renderer, persists changes on exit, 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.
|
|
2078
2231
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
2079
2232
|
* @param[in] ctx {ExtensionCommandContext} Active command context.
|
|
2080
2233
|
* @param[in,out] statusController {PiUsereqStatusController} Mutable status controller.
|
|
2081
2234
|
* @return {Promise<void>} Promise resolved when configuration is saved and the menu closes.
|
|
2082
|
-
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154
|
|
2235
|
+
* @satisfies REQ-006, REQ-031, REQ-137, REQ-150, REQ-151, REQ-152, REQ-153, REQ-154, REQ-162
|
|
2083
2236
|
*/
|
|
2084
2237
|
async function configurePiUsereq(
|
|
2085
2238
|
pi: ExtensionAPI,
|
|
@@ -2096,7 +2249,11 @@ async function configurePiUsereq(
|
|
|
2096
2249
|
};
|
|
2097
2250
|
|
|
2098
2251
|
while (true) {
|
|
2099
|
-
const choice = await showPiUsereqSettingsMenu(
|
|
2252
|
+
const choice = await showPiUsereqSettingsMenu(
|
|
2253
|
+
ctx,
|
|
2254
|
+
"pi-usereq",
|
|
2255
|
+
buildPiUsereqMenuChoices(ctx.cwd, config),
|
|
2256
|
+
);
|
|
2100
2257
|
if (!choice || choice === "save-and-close") {
|
|
2101
2258
|
ensureSaved();
|
|
2102
2259
|
refreshStatus();
|
|
@@ -2190,18 +2347,20 @@ function registerConfigCommands(
|
|
|
2190
2347
|
* configuration commands plus agent tools, registers the configurable
|
|
2191
2348
|
* successful-run sound shortcut when the runtime supports shortcuts, and
|
|
2192
2349
|
* installs shared wrappers for all supported pi lifecycle hooks so status
|
|
2193
|
-
* telemetry, context usage, prompt timing,
|
|
2194
|
-
*
|
|
2195
|
-
*
|
|
2196
|
-
*
|
|
2350
|
+
* telemetry, context usage, prompt timing, cumulative runtime, prompt-specific
|
|
2351
|
+
* Pushover metadata, and pi-notify effects remain synchronized with runtime
|
|
2352
|
+
* events. Runtime is O(h) in hook
|
|
2353
|
+
* count during registration. Side effects include filesystem reads,
|
|
2354
|
+
* command/tool/shortcut registration, UI updates, active-tool changes, and
|
|
2355
|
+
* timer scheduling.
|
|
2197
2356
|
* @param[in] pi {ExtensionAPI} Active extension API instance.
|
|
2198
2357
|
* @return {void} No return value.
|
|
2199
|
-
* @satisfies DES-002, REQ-004, REQ-005, REQ-009, REQ-044, REQ-045, REQ-067, REQ-068, REQ-109, REQ-
|
|
2358
|
+
* @satisfies DES-002, REQ-004, REQ-005, REQ-009, REQ-044, REQ-045, REQ-067, REQ-068, REQ-109, REQ-111, REQ-112, REQ-113, REQ-114, REQ-115, REQ-116, REQ-117, REQ-118, REQ-119, REQ-120, REQ-121, REQ-122, REQ-123, REQ-124, REQ-125, REQ-126, REQ-129, REQ-130, REQ-131, REQ-132, REQ-133, REQ-134, REQ-135, REQ-136, REQ-137, REQ-148, REQ-159, REQ-163, REQ-164, REQ-165, REQ-166, REQ-167, REQ-168, REQ-169, REQ-170, REQ-171, REQ-172
|
|
2200
2359
|
*/
|
|
2201
2360
|
export default function piUsereqExtension(pi: ExtensionAPI): void {
|
|
2202
|
-
const statusController = createPiUsereqStatusController(
|
|
2361
|
+
const statusController = createPiUsereqStatusController();
|
|
2203
2362
|
ensureBundledResourcesAccessible();
|
|
2204
|
-
registerPromptCommands(pi);
|
|
2363
|
+
registerPromptCommands(pi, statusController);
|
|
2205
2364
|
registerAgentTools(pi);
|
|
2206
2365
|
registerConfigCommands(pi, statusController);
|
|
2207
2366
|
registerPiNotifyShortcut(pi, statusController);
|