@unbrained/pm-cli 2026.5.3 → 2026.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +9 -1
- package/dist/cli/main.js +269 -15
- package/dist/cli/main.js.map +1 -1
- package/dist/core/sentry/helpers.d.ts +15 -2
- package/dist/core/sentry/helpers.js +73 -3
- package/dist/core/sentry/helpers.js.map +1 -1
- package/dist/core/shared/constants.js +3 -0
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/telemetry/observability.d.ts +24 -0
- package/dist/core/telemetry/observability.js +185 -0
- package/dist/core/telemetry/observability.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +6 -0
- package/dist/core/telemetry/runtime.js +132 -7
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/docs/CONFIGURATION.md +0 -2
- package/docs/RELEASING.md +43 -39
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,54 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2026.5.4] - 2026-05-04
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Relaxed release workflow npx/bunx post-publish checks to emit warnings instead of hard-failing the pipeline when registry/executor convergence lags, while keeping npm publication metadata as a blocking verification gate.
|
|
14
|
+
|
|
15
|
+
## [2026.5.3-8] - 2026-05-03
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- Updated release workflow npx verification to run the explicit package binary command (`npx @unbrained/pm-cli@<version> pm --version`) to avoid npm exec binary resolution drift on GitHub-hosted runners.
|
|
19
|
+
|
|
20
|
+
## [2026.5.3-7] - 2026-05-03
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Updated release post-publish verification commands to execute the package `pm` binary explicitly (`npm exec --package ... -- pm --version` and `bunx ... pm --version`) and parse terminal line output robustly.
|
|
24
|
+
|
|
25
|
+
## [2026.5.3-6] - 2026-05-03
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Added npm/npx/bunx propagation retries to release publication verification so post-publish checks wait for registry availability instead of failing immediately on transient 404 windows.
|
|
29
|
+
|
|
30
|
+
## [2026.5.3-5] - 2026-05-03
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- Hardened release workflow reliability gating so Sentry threshold checks are skipped when the runner does not provide the `sentry` CLI binary, preventing false-negative publish blocks on GitHub-hosted runners.
|
|
34
|
+
|
|
35
|
+
## [2026.5.3-4] - 2026-05-03
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- Relaxed tag release version policy guard in `.github/workflows/release.yml` to validate tag/version consistency without blocking same-day retry tags when a previous tag run failed before npm publication.
|
|
39
|
+
- Hardened `scripts/release/run-release-pipeline.mjs` same-day retry version resolution so local retry cuts always advance beyond the currently checked-out package version when npm has not yet observed failed prior tags.
|
|
40
|
+
|
|
41
|
+
## [2026.5.3-3] - 2026-05-03
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- Relaxed release compatibility health evaluation so compatibility gating only blocks on failing health checks, not warning-only health states, preventing false negatives on GitHub-hosted release runs.
|
|
45
|
+
|
|
46
|
+
## [2026.5.3-2] - 2026-05-03
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- Added a scheduled auto-release workflow (`.github/workflows/auto-release.yml`) with one-release-per-UTC-day defaults, manual same-day override controls, and a shared release pipeline driver.
|
|
50
|
+
- Added release automation scripts under `scripts/release/` for changelog promotion, strict static quality checks, temporary-project backward-compatibility validation, Sentry/telemetry threshold gating, unified release gate execution, and full local pipeline orchestration.
|
|
51
|
+
- Added release automation contract coverage in `tests/integration/release-automation-contract.spec.ts`.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
- Hardened CI, nightly, and release workflows with explicit static quality and compatibility migration gates.
|
|
55
|
+
- Release workflow now verifies published package availability via npm, npx, and bunx, and verifies GitHub release metadata after publication.
|
|
56
|
+
- Expanded release-readiness runtime checks to cover new release scripts, package commands, and auto-release workflow presence.
|
|
57
|
+
|
|
10
58
|
## [2026.5.3] - 2026-05-03
|
|
11
59
|
|
|
12
60
|
### Added
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
| Settings, storage, search, and output | [Configuration](docs/CONFIGURATION.md) |
|
|
18
18
|
| Safe test execution and linked tests | [Testing](docs/TESTING.md) |
|
|
19
19
|
| Extension authoring | [Extensions](docs/EXTENSIONS.md) and [SDK](docs/SDK.md) |
|
|
20
|
-
| Maintainer release process | [Releasing](docs/RELEASING.md) |
|
|
20
|
+
| Maintainer release process (daily auto-release + local parity) | [Releasing](docs/RELEASING.md) |
|
|
21
21
|
| Contributor internals | [Architecture](docs/ARCHITECTURE.md) |
|
|
22
22
|
|
|
23
23
|
Full documentation starts at [docs/README.md](docs/README.md).
|
|
@@ -76,6 +76,14 @@ pm list-in-progress --limit 20
|
|
|
76
76
|
|
|
77
77
|
If no relevant item exists, create a parent lineage before child work, claim the child item, link changed files/docs/tests, and leave evidence comments before closing. The full workflow is in the [Agent Guide](docs/AGENT_GUIDE.md).
|
|
78
78
|
|
|
79
|
+
## Release Automation
|
|
80
|
+
|
|
81
|
+
- Daily release preparation runs in `.github/workflows/auto-release.yml`.
|
|
82
|
+
- Tag-driven publishing remains in `.github/workflows/release.yml`.
|
|
83
|
+
- Local parity commands:
|
|
84
|
+
- `pnpm release:pipeline:dry-run`
|
|
85
|
+
- `pnpm release:pipeline -- --telemetry-mode required`
|
|
86
|
+
|
|
79
87
|
## Core Model
|
|
80
88
|
|
|
81
89
|
- Items live under `.agents/pm/` as TOON by default, with JSON-front-matter markdown also supported.
|
package/dist/cli/main.js
CHANGED
|
@@ -12,6 +12,7 @@ import { PmCliError } from "../core/shared/errors.js";
|
|
|
12
12
|
import { printError, printResult, writeStdout } from "../core/output/output.js";
|
|
13
13
|
import { maybeRunFirstUseTelemetryPrompt } from "../core/telemetry/consent.js";
|
|
14
14
|
import { emitTelemetryErrorEvent, finishTelemetryCommand, startTelemetryCommand, } from "../core/telemetry/runtime.js";
|
|
15
|
+
import { deriveTelemetryCommandResolution, } from "../core/telemetry/observability.js";
|
|
15
16
|
import { sentryCaptureCliError, sentryFinishCommandSpan, sentryFlush, sentryLogCliUsageError, sentrySetCommandContext, sentryStartCommandSpan, } from "../core/sentry/helpers.js";
|
|
16
17
|
import { getSettingsPath, resolvePmRoot } from "../core/store/paths.js";
|
|
17
18
|
import { readSettings } from "../core/store/settings.js";
|
|
@@ -38,6 +39,20 @@ if (typeof process.env[PM_PACKAGE_ROOT_ENV] !== "string" || process.env[PM_PACKA
|
|
|
38
39
|
}
|
|
39
40
|
let activeExtensionHookContext = null;
|
|
40
41
|
let activeTelemetryCommandContext = null;
|
|
42
|
+
const TELEMETRY_COMMAND_RESOLUTION_SET = new Set([
|
|
43
|
+
"success",
|
|
44
|
+
"nonexistent_command",
|
|
45
|
+
"invalid_option",
|
|
46
|
+
"missing_required_option",
|
|
47
|
+
"missing_required_argument",
|
|
48
|
+
"invalid_usage",
|
|
49
|
+
"validation_failed",
|
|
50
|
+
"conflict",
|
|
51
|
+
"runtime_failed",
|
|
52
|
+
"unknown_failed",
|
|
53
|
+
]);
|
|
54
|
+
const TELEMETRY_RESOLUTION_STAGE_SET = new Set(["parse", "preflight", "execute", "unknown"]);
|
|
55
|
+
const TELEMETRY_ERROR_CATEGORY_SET = new Set(["usage", "validation", "conflict", "runtime", "unknown"]);
|
|
41
56
|
let runtimeExtensionSnapshotCache = null;
|
|
42
57
|
let activeRuntimeExtensionCommandDescriptors = new Map();
|
|
43
58
|
function describeUnknownError(error) {
|
|
@@ -49,6 +64,163 @@ function describeUnknownError(error) {
|
|
|
49
64
|
}
|
|
50
65
|
return "Unknown failure";
|
|
51
66
|
}
|
|
67
|
+
function asRecord(value) {
|
|
68
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
function readRecordString(record, ...keys) {
|
|
74
|
+
if (!record) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
for (const key of keys) {
|
|
78
|
+
const candidate = record[key];
|
|
79
|
+
if (typeof candidate === "string") {
|
|
80
|
+
const normalized = candidate.trim();
|
|
81
|
+
if (normalized.length > 0) {
|
|
82
|
+
return normalized;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function readRecordBoolean(record, ...keys) {
|
|
89
|
+
if (!record) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
for (const key of keys) {
|
|
93
|
+
const candidate = record[key];
|
|
94
|
+
if (typeof candidate === "boolean") {
|
|
95
|
+
return candidate;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
function readRecordNumber(record, ...keys) {
|
|
101
|
+
if (!record) {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
for (const key of keys) {
|
|
105
|
+
const candidate = record[key];
|
|
106
|
+
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
107
|
+
return Math.max(0, Math.trunc(candidate));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
function normalizeTelemetryCommandResolution(value) {
|
|
113
|
+
if (!value) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const normalized = value.trim().toLowerCase();
|
|
117
|
+
if (!TELEMETRY_COMMAND_RESOLUTION_SET.has(normalized)) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return normalized;
|
|
121
|
+
}
|
|
122
|
+
function normalizeTelemetryResolutionStage(value) {
|
|
123
|
+
if (!value) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const normalized = value.trim().toLowerCase();
|
|
127
|
+
if (!TELEMETRY_RESOLUTION_STAGE_SET.has(normalized)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return normalized;
|
|
131
|
+
}
|
|
132
|
+
function normalizeTelemetryErrorCategory(value) {
|
|
133
|
+
if (!value) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const normalized = value.trim().toLowerCase();
|
|
137
|
+
if (!TELEMETRY_ERROR_CATEGORY_SET.has(normalized)) {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
return normalized;
|
|
141
|
+
}
|
|
142
|
+
function inferPostActionFailureMessage(result) {
|
|
143
|
+
const explicit = readRecordString(result, "error", "message");
|
|
144
|
+
if (explicit) {
|
|
145
|
+
return explicit;
|
|
146
|
+
}
|
|
147
|
+
const warnings = result?.warnings;
|
|
148
|
+
if (Array.isArray(warnings)) {
|
|
149
|
+
const firstWarning = warnings.find((value) => typeof value === "string" && value.trim().length > 0);
|
|
150
|
+
if (typeof firstWarning === "string") {
|
|
151
|
+
return firstWarning.trim();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const skippedTriggered = readRecordBoolean(result, "fail_on_skipped_triggered", "failOnSkippedTriggered");
|
|
155
|
+
if (skippedTriggered) {
|
|
156
|
+
return "linked_test_fail_on_skipped_triggered";
|
|
157
|
+
}
|
|
158
|
+
const failedCount = readRecordNumber(result, "failed");
|
|
159
|
+
if (typeof failedCount === "number" && failedCount > 0) {
|
|
160
|
+
return `failed_runs:${failedCount}`;
|
|
161
|
+
}
|
|
162
|
+
const runResults = result?.run_results;
|
|
163
|
+
if (Array.isArray(runResults)) {
|
|
164
|
+
const failedRuns = runResults.filter((entry) => {
|
|
165
|
+
const row = asRecord(entry);
|
|
166
|
+
return row?.status === "failed";
|
|
167
|
+
}).length;
|
|
168
|
+
if (failedRuns > 0) {
|
|
169
|
+
return `failed_runs:${failedRuns}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
function inferPostActionErrorCode(ok, exitCode) {
|
|
175
|
+
if (ok) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
if (exitCode === EXIT_CODE.USAGE) {
|
|
179
|
+
return "invalid_command_usage";
|
|
180
|
+
}
|
|
181
|
+
if (exitCode === EXIT_CODE.NOT_FOUND) {
|
|
182
|
+
return "item_not_found";
|
|
183
|
+
}
|
|
184
|
+
if (exitCode === EXIT_CODE.CONFLICT) {
|
|
185
|
+
return "lock_conflict";
|
|
186
|
+
}
|
|
187
|
+
if (exitCode === EXIT_CODE.DEPENDENCY_FAILED) {
|
|
188
|
+
return "dependency_failed";
|
|
189
|
+
}
|
|
190
|
+
return "command_failed";
|
|
191
|
+
}
|
|
192
|
+
function buildPostActionTelemetryOutcome() {
|
|
193
|
+
const result = asRecord(getActiveCommandResult());
|
|
194
|
+
const processExitCode = typeof process.exitCode === "number" && Number.isFinite(process.exitCode)
|
|
195
|
+
? Math.max(0, Math.trunc(process.exitCode))
|
|
196
|
+
: undefined;
|
|
197
|
+
const resultExitCode = readRecordNumber(result, "exit_code", "exitCode");
|
|
198
|
+
const exitCode = processExitCode ?? resultExitCode ?? EXIT_CODE.SUCCESS;
|
|
199
|
+
const resultOk = readRecordBoolean(result, "ok");
|
|
200
|
+
const ok = resultOk ?? exitCode === EXIT_CODE.SUCCESS;
|
|
201
|
+
const errorCode = readRecordString(result, "error_code", "errorCode") ?? inferPostActionErrorCode(ok, exitCode);
|
|
202
|
+
const errorCategory = normalizeTelemetryErrorCategory(readRecordString(result, "error_category", "errorCategory")) ??
|
|
203
|
+
(!ok ? resolveTelemetryErrorCategory(errorCode) : undefined);
|
|
204
|
+
const errorMessage = !ok
|
|
205
|
+
? inferPostActionFailureMessage(result) ?? `command_exit_${exitCode}`
|
|
206
|
+
: undefined;
|
|
207
|
+
const commandResolution = normalizeTelemetryCommandResolution(readRecordString(result, "command_resolution", "commandResolution")) ??
|
|
208
|
+
deriveTelemetryCommandResolution({
|
|
209
|
+
ok,
|
|
210
|
+
errorCode,
|
|
211
|
+
errorCategory,
|
|
212
|
+
});
|
|
213
|
+
const resolutionStage = normalizeTelemetryResolutionStage(readRecordString(result, "resolution_stage", "resolutionStage")) ?? "execute";
|
|
214
|
+
return {
|
|
215
|
+
ok,
|
|
216
|
+
error: errorMessage,
|
|
217
|
+
exit_code: exitCode,
|
|
218
|
+
error_code: errorCode,
|
|
219
|
+
error_category: errorCategory,
|
|
220
|
+
command_resolution: commandResolution,
|
|
221
|
+
resolution_stage: resolutionStage,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
52
224
|
async function runAndClearAfterCommandHooks(outcome) {
|
|
53
225
|
const telemetryRuntime = activeTelemetryCommandContext;
|
|
54
226
|
activeTelemetryCommandContext = null;
|
|
@@ -59,6 +231,8 @@ async function runAndClearAfterCommandHooks(outcome) {
|
|
|
59
231
|
exit_code: outcome.exit_code,
|
|
60
232
|
error_code: outcome.error_code,
|
|
61
233
|
error_category: outcome.error_category,
|
|
234
|
+
command_resolution: outcome.command_resolution,
|
|
235
|
+
resolution_stage: outcome.resolution_stage,
|
|
62
236
|
});
|
|
63
237
|
const runtime = activeExtensionHookContext;
|
|
64
238
|
activeExtensionHookContext = null;
|
|
@@ -640,7 +814,10 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
640
814
|
global: globalOptions,
|
|
641
815
|
pm_root: fallbackPmRoot,
|
|
642
816
|
});
|
|
643
|
-
sentrySetCommandContext(commandPath, commandArgs, commandOptions
|
|
817
|
+
sentrySetCommandContext(commandPath, commandArgs, commandOptions, {
|
|
818
|
+
source_context: activeTelemetryCommandContext?.source_context,
|
|
819
|
+
source_context_source: activeTelemetryCommandContext?.source_context_source,
|
|
820
|
+
});
|
|
644
821
|
sentryStartCommandSpan(commandPath);
|
|
645
822
|
await enforceItemFormatWriteGateAndPreflightMigration(commandPath, commandOptions, fallbackPmRoot, defaultPreflightDecision());
|
|
646
823
|
return;
|
|
@@ -716,7 +893,10 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
716
893
|
global: globalOptions,
|
|
717
894
|
pm_root: runtimeExtensions.pmRoot,
|
|
718
895
|
});
|
|
719
|
-
sentrySetCommandContext(commandPath, commandArgs, commandOptions
|
|
896
|
+
sentrySetCommandContext(commandPath, commandArgs, commandOptions, {
|
|
897
|
+
source_context: activeTelemetryCommandContext?.source_context,
|
|
898
|
+
source_context_source: activeTelemetryCommandContext?.source_context_source,
|
|
899
|
+
});
|
|
720
900
|
sentryStartCommandSpan(commandPath);
|
|
721
901
|
const hookWarnings = await runBeforeCommandHooks(runtimeExtensions.hooks, {
|
|
722
902
|
command: commandPath,
|
|
@@ -733,8 +913,15 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
733
913
|
}
|
|
734
914
|
});
|
|
735
915
|
program.hook("postAction", async () => {
|
|
736
|
-
|
|
737
|
-
|
|
916
|
+
const outcome = buildPostActionTelemetryOutcome();
|
|
917
|
+
sentryFinishCommandSpan(outcome.ok, outcome.error, {
|
|
918
|
+
error_code: outcome.error_code,
|
|
919
|
+
error_category: outcome.error_category,
|
|
920
|
+
exit_code: outcome.exit_code,
|
|
921
|
+
command_resolution: outcome.command_resolution,
|
|
922
|
+
resolution_stage: outcome.resolution_stage,
|
|
923
|
+
});
|
|
924
|
+
await runAndClearAfterCommandHooks(outcome);
|
|
738
925
|
});
|
|
739
926
|
registerSetupCommands(program);
|
|
740
927
|
registerListQueryCommands(program);
|
|
@@ -762,6 +949,11 @@ async function main() {
|
|
|
762
949
|
const attemptedCommand = parseBootstrapCommandName(invocationArgv) ?? "<unknown>";
|
|
763
950
|
const emitTelemetryCommandError = async (params) => {
|
|
764
951
|
const errorCategory = resolveTelemetryErrorCategory(params.errorCode);
|
|
952
|
+
const commandResolution = deriveTelemetryCommandResolution({
|
|
953
|
+
ok: false,
|
|
954
|
+
errorCode: params.errorCode,
|
|
955
|
+
errorCategory,
|
|
956
|
+
});
|
|
765
957
|
await emitTelemetryErrorEvent({
|
|
766
958
|
command: params.command,
|
|
767
959
|
args: invocationArgv,
|
|
@@ -773,8 +965,13 @@ async function main() {
|
|
|
773
965
|
error_message: params.errorMessage,
|
|
774
966
|
exit_code: params.exitCode,
|
|
775
967
|
error_category: errorCategory,
|
|
968
|
+
command_resolution: commandResolution,
|
|
969
|
+
resolution_stage: params.resolutionStage,
|
|
776
970
|
});
|
|
777
|
-
return
|
|
971
|
+
return {
|
|
972
|
+
errorCategory,
|
|
973
|
+
commandResolution,
|
|
974
|
+
};
|
|
778
975
|
};
|
|
779
976
|
if (!bootstrapGlobal.noExtensions) {
|
|
780
977
|
const bootstrapSnapshot = await loadRuntimeExtensionSnapshot(bootstrapPmRoot);
|
|
@@ -782,7 +979,7 @@ async function main() {
|
|
|
782
979
|
}
|
|
783
980
|
if (error instanceof PmCliError) {
|
|
784
981
|
const classification = classifyPmCliError(error.message, error.context);
|
|
785
|
-
const errorCategory = await emitTelemetryCommandError({
|
|
982
|
+
const { errorCategory, commandResolution } = await emitTelemetryCommandError({
|
|
786
983
|
command: attemptedCommand,
|
|
787
984
|
errorCode: classification.code,
|
|
788
985
|
errorMessage: classification.detail,
|
|
@@ -790,6 +987,7 @@ async function main() {
|
|
|
790
987
|
options: {
|
|
791
988
|
bootstrap_global_options: bootstrapGlobal,
|
|
792
989
|
},
|
|
990
|
+
resolutionStage: "execute",
|
|
793
991
|
});
|
|
794
992
|
sentryLogCliUsageError({
|
|
795
993
|
command: attemptedCommand,
|
|
@@ -797,14 +995,25 @@ async function main() {
|
|
|
797
995
|
error_category: errorCategory,
|
|
798
996
|
exit_code: error.exitCode,
|
|
799
997
|
error_message: classification.detail,
|
|
998
|
+
command_resolution: commandResolution,
|
|
999
|
+
resolution_stage: "execute",
|
|
1000
|
+
source_context: activeTelemetryCommandContext?.source_context,
|
|
1001
|
+
});
|
|
1002
|
+
sentryFinishCommandSpan(false, error.message, {
|
|
1003
|
+
error_code: classification.code,
|
|
1004
|
+
error_category: errorCategory,
|
|
1005
|
+
exit_code: error.exitCode,
|
|
1006
|
+
command_resolution: commandResolution,
|
|
1007
|
+
resolution_stage: "execute",
|
|
800
1008
|
});
|
|
801
|
-
sentryFinishCommandSpan(false, error.message);
|
|
802
1009
|
await runAndClearAfterCommandHooks({
|
|
803
1010
|
ok: false,
|
|
804
1011
|
error: error.message,
|
|
805
1012
|
exit_code: error.exitCode,
|
|
806
1013
|
error_code: classification.code,
|
|
807
1014
|
error_category: errorCategory,
|
|
1015
|
+
command_resolution: commandResolution,
|
|
1016
|
+
resolution_stage: "execute",
|
|
808
1017
|
});
|
|
809
1018
|
sentryCaptureCliError(error);
|
|
810
1019
|
if (jsonErrors) {
|
|
@@ -831,7 +1040,7 @@ async function main() {
|
|
|
831
1040
|
unknownCommandExamples: usageContext.unknownCommandExamples,
|
|
832
1041
|
unknownCommandNextSteps: usageContext.unknownCommandNextSteps,
|
|
833
1042
|
});
|
|
834
|
-
const errorCategory = await emitTelemetryCommandError({
|
|
1043
|
+
const { errorCategory, commandResolution } = await emitTelemetryCommandError({
|
|
835
1044
|
command: unknownToken,
|
|
836
1045
|
errorCode: classification.code,
|
|
837
1046
|
errorMessage: classification.detail,
|
|
@@ -840,6 +1049,7 @@ async function main() {
|
|
|
840
1049
|
bootstrap_global_options: bootstrapGlobal,
|
|
841
1050
|
commander_code: code ?? "commander.helpDisplayed",
|
|
842
1051
|
},
|
|
1052
|
+
resolutionStage: "parse",
|
|
843
1053
|
});
|
|
844
1054
|
sentryLogCliUsageError({
|
|
845
1055
|
command: unknownToken,
|
|
@@ -847,17 +1057,28 @@ async function main() {
|
|
|
847
1057
|
error_category: errorCategory,
|
|
848
1058
|
exit_code: EXIT_CODE.USAGE,
|
|
849
1059
|
error_message: classification.detail,
|
|
1060
|
+
command_resolution: commandResolution,
|
|
1061
|
+
resolution_stage: "parse",
|
|
1062
|
+
source_context: activeTelemetryCommandContext?.source_context,
|
|
850
1063
|
});
|
|
851
1064
|
const renderedUsage = jsonErrors
|
|
852
1065
|
? await formatCommanderUsageJson({ message: unknownMessage }, program, activeRuntimeExtensionCommandDescriptors)
|
|
853
1066
|
: await formatCommanderUsageMessage({ message: unknownMessage }, program, activeRuntimeExtensionCommandDescriptors);
|
|
854
|
-
sentryFinishCommandSpan(false, unknownMessage
|
|
1067
|
+
sentryFinishCommandSpan(false, unknownMessage, {
|
|
1068
|
+
error_code: classification.code,
|
|
1069
|
+
error_category: errorCategory,
|
|
1070
|
+
exit_code: EXIT_CODE.USAGE,
|
|
1071
|
+
command_resolution: commandResolution,
|
|
1072
|
+
resolution_stage: "parse",
|
|
1073
|
+
});
|
|
855
1074
|
await runAndClearAfterCommandHooks({
|
|
856
1075
|
ok: false,
|
|
857
1076
|
error: unknownMessage,
|
|
858
1077
|
exit_code: EXIT_CODE.USAGE,
|
|
859
1078
|
error_code: classification.code,
|
|
860
1079
|
error_category: errorCategory,
|
|
1080
|
+
command_resolution: commandResolution,
|
|
1081
|
+
resolution_stage: "parse",
|
|
861
1082
|
});
|
|
862
1083
|
if (jsonErrors) {
|
|
863
1084
|
printError(renderedUsage);
|
|
@@ -869,19 +1090,31 @@ async function main() {
|
|
|
869
1090
|
process.exitCode = EXIT_CODE.USAGE;
|
|
870
1091
|
return;
|
|
871
1092
|
}
|
|
872
|
-
sentryFinishCommandSpan(true
|
|
1093
|
+
sentryFinishCommandSpan(true, undefined, {
|
|
1094
|
+
exit_code: EXIT_CODE.SUCCESS,
|
|
1095
|
+
command_resolution: "success",
|
|
1096
|
+
resolution_stage: "parse",
|
|
1097
|
+
});
|
|
873
1098
|
await runAndClearAfterCommandHooks({
|
|
874
1099
|
ok: true,
|
|
875
1100
|
exit_code: EXIT_CODE.SUCCESS,
|
|
1101
|
+
command_resolution: "success",
|
|
1102
|
+
resolution_stage: "parse",
|
|
876
1103
|
});
|
|
877
1104
|
process.exitCode = EXIT_CODE.SUCCESS;
|
|
878
1105
|
return;
|
|
879
1106
|
}
|
|
880
1107
|
if (code === "commander.version") {
|
|
881
|
-
sentryFinishCommandSpan(true
|
|
1108
|
+
sentryFinishCommandSpan(true, undefined, {
|
|
1109
|
+
exit_code: EXIT_CODE.SUCCESS,
|
|
1110
|
+
command_resolution: "success",
|
|
1111
|
+
resolution_stage: "parse",
|
|
1112
|
+
});
|
|
882
1113
|
await runAndClearAfterCommandHooks({
|
|
883
1114
|
ok: true,
|
|
884
1115
|
exit_code: EXIT_CODE.SUCCESS,
|
|
1116
|
+
command_resolution: "success",
|
|
1117
|
+
resolution_stage: "parse",
|
|
885
1118
|
});
|
|
886
1119
|
process.exitCode = EXIT_CODE.SUCCESS;
|
|
887
1120
|
return;
|
|
@@ -892,7 +1125,7 @@ async function main() {
|
|
|
892
1125
|
unknownCommandExamples: usageContext.unknownCommandExamples,
|
|
893
1126
|
unknownCommandNextSteps: usageContext.unknownCommandNextSteps,
|
|
894
1127
|
});
|
|
895
|
-
const errorCategory = await emitTelemetryCommandError({
|
|
1128
|
+
const { errorCategory, commandResolution } = await emitTelemetryCommandError({
|
|
896
1129
|
command: attemptedCommand,
|
|
897
1130
|
errorCode: classification.code,
|
|
898
1131
|
errorMessage: classification.detail,
|
|
@@ -901,6 +1134,7 @@ async function main() {
|
|
|
901
1134
|
bootstrap_global_options: bootstrapGlobal,
|
|
902
1135
|
commander_code: code,
|
|
903
1136
|
},
|
|
1137
|
+
resolutionStage: "parse",
|
|
904
1138
|
});
|
|
905
1139
|
sentryLogCliUsageError({
|
|
906
1140
|
command: attemptedCommand,
|
|
@@ -908,17 +1142,28 @@ async function main() {
|
|
|
908
1142
|
error_category: errorCategory,
|
|
909
1143
|
exit_code: EXIT_CODE.USAGE,
|
|
910
1144
|
error_message: classification.detail,
|
|
1145
|
+
command_resolution: commandResolution,
|
|
1146
|
+
resolution_stage: "parse",
|
|
1147
|
+
source_context: activeTelemetryCommandContext?.source_context,
|
|
911
1148
|
});
|
|
912
1149
|
const renderedUsage = jsonErrors
|
|
913
1150
|
? await formatCommanderUsageJson(error, program, activeRuntimeExtensionCommandDescriptors)
|
|
914
1151
|
: await formatCommanderUsageMessage(error, program, activeRuntimeExtensionCommandDescriptors);
|
|
915
|
-
sentryFinishCommandSpan(false, usageContext.message
|
|
1152
|
+
sentryFinishCommandSpan(false, usageContext.message, {
|
|
1153
|
+
error_code: classification.code,
|
|
1154
|
+
error_category: errorCategory,
|
|
1155
|
+
exit_code: EXIT_CODE.USAGE,
|
|
1156
|
+
command_resolution: commandResolution,
|
|
1157
|
+
resolution_stage: "parse",
|
|
1158
|
+
});
|
|
916
1159
|
await runAndClearAfterCommandHooks({
|
|
917
1160
|
ok: false,
|
|
918
1161
|
error: usageContext.message,
|
|
919
1162
|
exit_code: EXIT_CODE.USAGE,
|
|
920
1163
|
error_code: classification.code,
|
|
921
1164
|
error_category: errorCategory,
|
|
1165
|
+
command_resolution: commandResolution,
|
|
1166
|
+
resolution_stage: "parse",
|
|
922
1167
|
});
|
|
923
1168
|
if (jsonErrors) {
|
|
924
1169
|
printError(renderedUsage);
|
|
@@ -934,7 +1179,7 @@ async function main() {
|
|
|
934
1179
|
sentryCaptureCliError(error);
|
|
935
1180
|
const message = describeUnknownError(error);
|
|
936
1181
|
const classification = classifyUnknownError(message);
|
|
937
|
-
const errorCategory = await emitTelemetryCommandError({
|
|
1182
|
+
const { errorCategory, commandResolution } = await emitTelemetryCommandError({
|
|
938
1183
|
command: attemptedCommand,
|
|
939
1184
|
errorCode: classification.code,
|
|
940
1185
|
errorMessage: classification.detail,
|
|
@@ -942,14 +1187,23 @@ async function main() {
|
|
|
942
1187
|
options: {
|
|
943
1188
|
bootstrap_global_options: bootstrapGlobal,
|
|
944
1189
|
},
|
|
1190
|
+
resolutionStage: "execute",
|
|
1191
|
+
});
|
|
1192
|
+
sentryFinishCommandSpan(false, message, {
|
|
1193
|
+
error_code: classification.code,
|
|
1194
|
+
error_category: errorCategory,
|
|
1195
|
+
exit_code: EXIT_CODE.GENERIC_FAILURE,
|
|
1196
|
+
command_resolution: commandResolution,
|
|
1197
|
+
resolution_stage: "execute",
|
|
945
1198
|
});
|
|
946
|
-
sentryFinishCommandSpan(false, message);
|
|
947
1199
|
await runAndClearAfterCommandHooks({
|
|
948
1200
|
ok: false,
|
|
949
1201
|
error: message,
|
|
950
1202
|
exit_code: EXIT_CODE.GENERIC_FAILURE,
|
|
951
1203
|
error_code: classification.code,
|
|
952
1204
|
error_category: errorCategory,
|
|
1205
|
+
command_resolution: commandResolution,
|
|
1206
|
+
resolution_stage: "execute",
|
|
953
1207
|
});
|
|
954
1208
|
if (jsonErrors) {
|
|
955
1209
|
printError(JSON.stringify(formatUnknownErrorForJson(message, EXIT_CODE.GENERIC_FAILURE), null, 2));
|