@unbrained/pm-cli 2026.3.12 → 2026.5.1
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/.agents/pm/extensions/.managed-extensions.json +42 -0
- package/.agents/pm/extensions/beads/index.js +109 -0
- package/.agents/pm/extensions/beads/manifest.json +7 -0
- package/{dist/cli/commands/beads.js → .agents/pm/extensions/beads/runtime.js} +31 -21
- package/.agents/pm/extensions/beads/runtime.ts +702 -0
- package/.agents/pm/extensions/todos/index.js +126 -0
- package/.agents/pm/extensions/todos/manifest.json +7 -0
- package/{dist/extensions/builtins/todos/import-export.js → .agents/pm/extensions/todos/runtime.js} +39 -29
- package/.agents/pm/extensions/todos/runtime.ts +568 -0
- package/AGENTS.md +196 -92
- package/CHANGELOG.md +399 -0
- package/CODE_OF_CONDUCT.md +42 -0
- package/CONTRIBUTING.md +144 -0
- package/PRD.md +512 -164
- package/README.md +1053 -2
- package/SECURITY.md +51 -0
- package/dist/cli/commands/activity.d.ts +5 -0
- package/dist/cli/commands/activity.js +66 -3
- package/dist/cli/commands/activity.js.map +1 -1
- package/dist/cli/commands/aggregate.d.ts +54 -0
- package/dist/cli/commands/aggregate.js +181 -0
- package/dist/cli/commands/aggregate.js.map +1 -0
- package/dist/cli/commands/append.js +4 -1
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.d.ts +109 -0
- package/dist/cli/commands/calendar.js +797 -0
- package/dist/cli/commands/calendar.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +5 -1
- package/dist/cli/commands/claim.js +42 -21
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.d.ts +1 -0
- package/dist/cli/commands/close.js +54 -5
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments-audit.d.ts +91 -0
- package/dist/cli/commands/comments-audit.js +195 -0
- package/dist/cli/commands/comments-audit.js.map +1 -0
- package/dist/cli/commands/comments.d.ts +1 -0
- package/dist/cli/commands/comments.js +70 -21
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +10 -4
- package/dist/cli/commands/completion.js +1184 -137
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +35 -3
- package/dist/cli/commands/config.js +968 -13
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.d.ts +86 -0
- package/dist/cli/commands/context.js +299 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/contracts.d.ts +78 -0
- package/dist/cli/commands/contracts.js +920 -0
- package/dist/cli/commands/contracts.js.map +1 -0
- package/dist/cli/commands/create.d.ts +48 -14
- package/dist/cli/commands/create.js +1331 -160
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.d.ts +81 -0
- package/dist/cli/commands/dedupe-audit.js +330 -0
- package/dist/cli/commands/dedupe-audit.js.map +1 -0
- package/dist/cli/commands/deps.d.ts +52 -0
- package/dist/cli/commands/deps.js +204 -0
- package/dist/cli/commands/deps.js.map +1 -0
- package/dist/cli/commands/docs.d.ts +19 -0
- package/dist/cli/commands/docs.js +212 -13
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +122 -0
- package/dist/cli/commands/extension.js +1850 -0
- package/dist/cli/commands/extension.js.map +1 -0
- package/dist/cli/commands/files.d.ts +52 -1
- package/dist/cli/commands/files.js +443 -13
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.d.ts +11 -1
- package/dist/cli/commands/gc.js +89 -11
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +13 -0
- package/dist/cli/commands/get.js +35 -3
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -2
- package/dist/cli/commands/health.js +774 -23
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +20 -0
- package/dist/cli/commands/history.js +152 -6
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +16 -3
- package/dist/cli/commands/index.js +16 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +7 -2
- package/dist/cli/commands/init.js +137 -5
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.d.ts +17 -0
- package/dist/cli/commands/learnings.js +129 -0
- package/dist/cli/commands/learnings.js.map +1 -0
- package/dist/cli/commands/list.d.ts +29 -1
- package/dist/cli/commands/list.js +289 -53
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.d.ts +51 -0
- package/dist/cli/commands/normalize.js +298 -0
- package/dist/cli/commands/normalize.js.map +1 -0
- package/dist/cli/commands/notes.d.ts +17 -0
- package/dist/cli/commands/notes.js +129 -0
- package/dist/cli/commands/notes.js.map +1 -0
- package/dist/cli/commands/reindex.d.ts +1 -0
- package/dist/cli/commands/reindex.js +208 -32
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/restore.js +164 -30
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/search.d.ts +14 -1
- package/dist/cli/commands/search.js +475 -81
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/stats.js +26 -10
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +26 -0
- package/dist/cli/commands/templates.js +179 -0
- package/dist/cli/commands/templates.js.map +1 -0
- package/dist/cli/commands/test-all.d.ts +19 -1
- package/dist/cli/commands/test-all.js +161 -13
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test-runs.d.ts +63 -0
- package/dist/cli/commands/test-runs.js +179 -0
- package/dist/cli/commands/test-runs.js.map +1 -0
- package/dist/cli/commands/test.d.ts +75 -1
- package/dist/cli/commands/test.js +1360 -41
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.d.ts +57 -0
- package/dist/cli/commands/update-many.js +631 -0
- package/dist/cli/commands/update-many.js.map +1 -0
- package/dist/cli/commands/update.d.ts +30 -0
- package/dist/cli/commands/update.js +1393 -84
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +30 -0
- package/dist/cli/commands/validate.js +1140 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/error-guidance.d.ts +33 -0
- package/dist/cli/error-guidance.js +337 -0
- package/dist/cli/error-guidance.js.map +1 -0
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +92 -0
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +20 -0
- package/dist/cli/help-content.js +543 -0
- package/dist/cli/help-content.js.map +1 -0
- package/dist/cli/main.js +3625 -445
- package/dist/cli/main.js.map +1 -1
- package/dist/core/extensions/index.d.ts +13 -1
- package/dist/core/extensions/index.js +108 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/item-fields.d.ts +2 -0
- package/dist/core/extensions/item-fields.js +79 -0
- package/dist/core/extensions/item-fields.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +322 -9
- package/dist/core/extensions/loader.js +911 -20
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runtime-registrations.d.ts +5 -0
- package/dist/core/extensions/runtime-registrations.js +51 -0
- package/dist/core/extensions/runtime-registrations.js.map +1 -0
- package/dist/core/history/history-stream-policy.d.ts +20 -0
- package/dist/core/history/history-stream-policy.js +53 -0
- package/dist/core/history/history-stream-policy.js.map +1 -0
- package/dist/core/history/history.js +90 -1
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/item/id.js +4 -1
- package/dist/core/item/id.js.map +1 -1
- package/dist/core/item/index.d.ts +1 -0
- package/dist/core/item/index.js +1 -0
- package/dist/core/item/index.js.map +1 -1
- package/dist/core/item/item-format.d.ts +11 -5
- package/dist/core/item/item-format.js +507 -24
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +6 -0
- package/dist/core/item/parent-reference-policy.js +32 -0
- package/dist/core/item/parent-reference-policy.js.map +1 -0
- package/dist/core/item/parse.d.ts +5 -0
- package/dist/core/item/parse.js +216 -19
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/sprint-release-format.d.ts +6 -0
- package/dist/core/item/sprint-release-format.js +33 -0
- package/dist/core/item/sprint-release-format.js.map +1 -0
- package/dist/core/item/status.d.ts +3 -0
- package/dist/core/item/status.js +24 -0
- package/dist/core/item/status.js.map +1 -0
- package/dist/core/item/type-registry.d.ts +37 -0
- package/dist/core/item/type-registry.js +706 -0
- package/dist/core/item/type-registry.js.map +1 -0
- package/dist/core/lock/lock.d.ts +1 -1
- package/dist/core/lock/lock.js +101 -12
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/output/command-aware.d.ts +1 -0
- package/dist/core/output/command-aware.js +394 -0
- package/dist/core/output/command-aware.js.map +1 -0
- package/dist/core/output/output.d.ts +3 -0
- package/dist/core/output/output.js +124 -6
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/schema/runtime-field-filters.d.ts +3 -0
- package/dist/core/schema/runtime-field-filters.js +39 -0
- package/dist/core/schema/runtime-field-filters.js.map +1 -0
- package/dist/core/schema/runtime-field-values.d.ts +8 -0
- package/dist/core/schema/runtime-field-values.js +154 -0
- package/dist/core/schema/runtime-field-values.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +68 -0
- package/dist/core/schema/runtime-schema.js +554 -0
- package/dist/core/schema/runtime-schema.js.map +1 -0
- package/dist/core/search/cache.d.ts +13 -1
- package/dist/core/search/cache.js +123 -14
- package/dist/core/search/cache.js.map +1 -1
- package/dist/core/search/semantic-defaults.d.ts +6 -0
- package/dist/core/search/semantic-defaults.js +120 -0
- package/dist/core/search/semantic-defaults.js.map +1 -0
- package/dist/core/search/vector-stores.js +3 -1
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/shared/command-types.d.ts +2 -0
- package/dist/core/shared/conflict-markers.d.ts +7 -0
- package/dist/core/shared/conflict-markers.js +27 -0
- package/dist/core/shared/conflict-markers.js.map +1 -0
- package/dist/core/shared/constants.d.ts +15 -4
- package/dist/core/shared/constants.js +141 -1
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +10 -1
- package/dist/core/shared/errors.js +3 -1
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +4 -0
- package/dist/core/shared/text-normalization.js +33 -0
- package/dist/core/shared/text-normalization.js.map +1 -0
- package/dist/core/shared/time.d.ts +1 -2
- package/dist/core/shared/time.js +98 -11
- package/dist/core/shared/time.js.map +1 -1
- package/dist/core/store/index.d.ts +1 -0
- package/dist/core/store/index.js +1 -0
- package/dist/core/store/index.js.map +1 -1
- package/dist/core/store/item-format-migration.d.ts +9 -0
- package/dist/core/store/item-format-migration.js +87 -0
- package/dist/core/store/item-format-migration.js.map +1 -0
- package/dist/core/store/item-store.d.ts +13 -4
- package/dist/core/store/item-store.js +238 -51
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/paths.d.ts +21 -3
- package/dist/core/store/paths.js +59 -4
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.d.ts +14 -1
- package/dist/core/store/settings.js +463 -7
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/consent.d.ts +2 -0
- package/dist/core/telemetry/consent.js +79 -0
- package/dist/core/telemetry/consent.js.map +1 -0
- package/dist/core/telemetry/runtime.d.ts +38 -0
- package/dist/core/telemetry/runtime.js +733 -0
- package/dist/core/telemetry/runtime.js.map +1 -0
- package/dist/core/test/background-runs.d.ts +117 -0
- package/dist/core/test/background-runs.js +760 -0
- package/dist/core/test/background-runs.js.map +1 -0
- package/dist/core/test/item-test-run-tracking.d.ts +9 -0
- package/dist/core/test/item-test-run-tracking.js +50 -0
- package/dist/core/test/item-test-run-tracking.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +92 -0
- package/dist/sdk/cli-contracts.js +2357 -0
- package/dist/sdk/cli-contracts.js.map +1 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +23 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/types.d.ts +197 -3
- package/dist/types.js +48 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +368 -39
- package/docs/EXTENSIONS.md +454 -49
- package/docs/RELEASING.md +68 -19
- package/docs/SDK.md +123 -0
- package/docs/examples/starter-extension/README.md +48 -0
- package/docs/examples/starter-extension/index.js +191 -0
- package/docs/examples/starter-extension/manifest.json +17 -0
- package/docs/examples/starter-extension/package.json +10 -0
- package/package.json +33 -6
- package/.pi/extensions/pm-cli/index.ts +0 -778
- package/dist/cli/commands/beads.d.ts +0 -16
- package/dist/cli/commands/beads.js.map +0 -1
- package/dist/cli/commands/install.d.ts +0 -18
- package/dist/cli/commands/install.js +0 -87
- package/dist/cli/commands/install.js.map +0 -1
- package/dist/core/extensions/builtins.d.ts +0 -3
- package/dist/core/extensions/builtins.js +0 -47
- package/dist/core/extensions/builtins.js.map +0 -1
- package/dist/extensions/builtins/beads/index.d.ts +0 -8
- package/dist/extensions/builtins/beads/index.js +0 -33
- package/dist/extensions/builtins/beads/index.js.map +0 -1
- package/dist/extensions/builtins/todos/import-export.d.ts +0 -26
- package/dist/extensions/builtins/todos/import-export.js.map +0 -1
- package/dist/extensions/builtins/todos/index.d.ts +0 -8
- package/dist/extensions/builtins/todos/index.js +0 -38
- package/dist/extensions/builtins/todos/index.js.map +0 -1
|
@@ -1,23 +1,438 @@
|
|
|
1
1
|
import { pathExists } from "../../core/fs/fs-utils.js";
|
|
2
|
-
import {
|
|
2
|
+
import { canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, } from "../../core/item/type-registry.js";
|
|
3
|
+
import { normalizeItemId } from "../../core/item/id.js";
|
|
4
|
+
import { normalizeParentReferenceValue, validateMissingParentReference, } from "../../core/item/parent-reference-policy.js";
|
|
5
|
+
import { validateSprintOrReleaseValue } from "../../core/item/sprint-release-format.js";
|
|
6
|
+
import { createStdinTokenResolver, parseCsvKv, parseOptionalNumber, parseTags } from "../../core/item/parse.js";
|
|
7
|
+
import { normalizeStatusInput } from "../../core/item/status.js";
|
|
8
|
+
import { collectRuntimeUpdateFieldValues } from "../../core/schema/runtime-field-values.js";
|
|
9
|
+
import { resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, } from "../../core/schema/runtime-schema.js";
|
|
3
10
|
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
4
11
|
import { PmCliError } from "../../core/shared/errors.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
12
|
+
import { resolveIsoOrRelative } from "../../core/shared/time.js";
|
|
13
|
+
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
14
|
+
import { applyRegisteredItemFieldDefaultsAndValidation } from "../../core/extensions/item-fields.js";
|
|
15
|
+
import { locateItem, mutateItem } from "../../core/store/item-store.js";
|
|
7
16
|
import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
|
|
8
17
|
import { readSettings } from "../../core/store/settings.js";
|
|
9
|
-
import { CONFIDENCE_TEXT_VALUES, ISSUE_SEVERITY_VALUES,
|
|
18
|
+
import { CONFIDENCE_TEXT_VALUES, DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RECURRENCE_FREQUENCY_VALUES, RECURRENCE_WEEKDAY_VALUES, RISK_VALUES, } from "../../types/index.js";
|
|
19
|
+
import { parseDocs, parseFiles, parseLogSeed, parseTests } from "./create.js";
|
|
20
|
+
const LEGACY_NONE_TOKENS = new Set(["none", "null"]);
|
|
21
|
+
const UPDATE_UNSET_FIELD_DEFINITIONS = [
|
|
22
|
+
{ canonical: "tags", aliases: ["tags"], optionKey: "tags", frontMatterKey: "tags" },
|
|
23
|
+
{ canonical: "close-reason", aliases: ["close_reason", "close-reason"], optionKey: "closeReason", frontMatterKey: "close_reason" },
|
|
24
|
+
{ canonical: "deadline", aliases: ["deadline"], optionKey: "deadline", frontMatterKey: "deadline" },
|
|
25
|
+
{
|
|
26
|
+
canonical: "estimate",
|
|
27
|
+
aliases: ["estimate", "estimated_minutes", "estimated-minutes"],
|
|
28
|
+
optionKey: "estimatedMinutes",
|
|
29
|
+
frontMatterKey: "estimated_minutes",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
canonical: "acceptance-criteria",
|
|
33
|
+
aliases: ["acceptance_criteria", "acceptance-criteria", "ac"],
|
|
34
|
+
optionKey: "acceptanceCriteria",
|
|
35
|
+
frontMatterKey: "acceptance_criteria",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
canonical: "definition-of-ready",
|
|
39
|
+
aliases: ["definition_of_ready", "definition-of-ready"],
|
|
40
|
+
optionKey: "definitionOfReady",
|
|
41
|
+
frontMatterKey: "definition_of_ready",
|
|
42
|
+
},
|
|
43
|
+
{ canonical: "order", aliases: ["order", "rank"], optionKey: "order", frontMatterKey: "order" },
|
|
44
|
+
{ canonical: "goal", aliases: ["goal"], optionKey: "goal", frontMatterKey: "goal" },
|
|
45
|
+
{ canonical: "objective", aliases: ["objective"], optionKey: "objective", frontMatterKey: "objective" },
|
|
46
|
+
{ canonical: "value", aliases: ["value"], optionKey: "value", frontMatterKey: "value" },
|
|
47
|
+
{ canonical: "impact", aliases: ["impact"], optionKey: "impact", frontMatterKey: "impact" },
|
|
48
|
+
{ canonical: "outcome", aliases: ["outcome"], optionKey: "outcome", frontMatterKey: "outcome" },
|
|
49
|
+
{ canonical: "why-now", aliases: ["why_now", "why-now"], optionKey: "whyNow", frontMatterKey: "why_now" },
|
|
50
|
+
{ canonical: "assignee", aliases: ["assignee"], optionKey: "assignee", frontMatterKey: "assignee" },
|
|
51
|
+
{ canonical: "parent", aliases: ["parent"], optionKey: "parent", frontMatterKey: "parent" },
|
|
52
|
+
{ canonical: "reviewer", aliases: ["reviewer"], optionKey: "reviewer", frontMatterKey: "reviewer" },
|
|
53
|
+
{ canonical: "risk", aliases: ["risk"], optionKey: "risk", frontMatterKey: "risk" },
|
|
54
|
+
{ canonical: "confidence", aliases: ["confidence"], optionKey: "confidence", frontMatterKey: "confidence" },
|
|
55
|
+
{ canonical: "sprint", aliases: ["sprint"], optionKey: "sprint", frontMatterKey: "sprint" },
|
|
56
|
+
{ canonical: "release", aliases: ["release"], optionKey: "release", frontMatterKey: "release" },
|
|
57
|
+
{
|
|
58
|
+
canonical: "blocked-by",
|
|
59
|
+
aliases: ["blocked_by", "blocked-by"],
|
|
60
|
+
optionKey: "blockedBy",
|
|
61
|
+
frontMatterKey: "blocked_by",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
canonical: "blocked-reason",
|
|
65
|
+
aliases: ["blocked_reason", "blocked-reason"],
|
|
66
|
+
optionKey: "blockedReason",
|
|
67
|
+
frontMatterKey: "blocked_reason",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
canonical: "unblock-note",
|
|
71
|
+
aliases: ["unblock_note", "unblock-note"],
|
|
72
|
+
optionKey: "unblockNote",
|
|
73
|
+
frontMatterKey: "unblock_note",
|
|
74
|
+
},
|
|
75
|
+
{ canonical: "reporter", aliases: ["reporter"], optionKey: "reporter", frontMatterKey: "reporter" },
|
|
76
|
+
{ canonical: "severity", aliases: ["severity"], optionKey: "severity", frontMatterKey: "severity" },
|
|
77
|
+
{
|
|
78
|
+
canonical: "environment",
|
|
79
|
+
aliases: ["environment"],
|
|
80
|
+
optionKey: "environment",
|
|
81
|
+
frontMatterKey: "environment",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
canonical: "repro-steps",
|
|
85
|
+
aliases: ["repro_steps", "repro-steps"],
|
|
86
|
+
optionKey: "reproSteps",
|
|
87
|
+
frontMatterKey: "repro_steps",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
canonical: "resolution",
|
|
91
|
+
aliases: ["resolution"],
|
|
92
|
+
optionKey: "resolution",
|
|
93
|
+
frontMatterKey: "resolution",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
canonical: "expected-result",
|
|
97
|
+
aliases: ["expected_result", "expected-result"],
|
|
98
|
+
optionKey: "expectedResult",
|
|
99
|
+
frontMatterKey: "expected_result",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
canonical: "actual-result",
|
|
103
|
+
aliases: ["actual_result", "actual-result"],
|
|
104
|
+
optionKey: "actualResult",
|
|
105
|
+
frontMatterKey: "actual_result",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
canonical: "affected-version",
|
|
109
|
+
aliases: ["affected_version", "affected-version"],
|
|
110
|
+
optionKey: "affectedVersion",
|
|
111
|
+
frontMatterKey: "affected_version",
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
canonical: "fixed-version",
|
|
115
|
+
aliases: ["fixed_version", "fixed-version"],
|
|
116
|
+
optionKey: "fixedVersion",
|
|
117
|
+
frontMatterKey: "fixed_version",
|
|
118
|
+
},
|
|
119
|
+
{ canonical: "component", aliases: ["component"], optionKey: "component", frontMatterKey: "component" },
|
|
120
|
+
{ canonical: "regression", aliases: ["regression"], optionKey: "regression", frontMatterKey: "regression" },
|
|
121
|
+
{
|
|
122
|
+
canonical: "customer-impact",
|
|
123
|
+
aliases: ["customer_impact", "customer-impact"],
|
|
124
|
+
optionKey: "customerImpact",
|
|
125
|
+
frontMatterKey: "customer_impact",
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
const UPDATE_UNSET_ALIAS_MAP = (() => {
|
|
129
|
+
const map = new Map();
|
|
130
|
+
for (const definition of UPDATE_UNSET_FIELD_DEFINITIONS) {
|
|
131
|
+
for (const alias of definition.aliases) {
|
|
132
|
+
map.set(alias, {
|
|
133
|
+
optionKey: definition.optionKey,
|
|
134
|
+
frontMatterKey: definition.frontMatterKey,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return map;
|
|
139
|
+
})();
|
|
140
|
+
const UPDATE_OPTION_KEY_TO_UNSET_CANONICAL = new Map(UPDATE_UNSET_FIELD_DEFINITIONS.map((definition) => [definition.optionKey, definition.canonical]));
|
|
141
|
+
const UPDATE_UNSET_SUPPORTED_CANONICAL_FIELDS = UPDATE_UNSET_FIELD_DEFINITIONS.map((definition) => definition.canonical)
|
|
142
|
+
.sort((left, right) => left.localeCompare(right))
|
|
143
|
+
.join(", ");
|
|
144
|
+
const AUDIT_UPDATE_DISALLOWED_UNSET_FRONT_MATTER_KEYS = new Set([
|
|
145
|
+
"close_reason",
|
|
146
|
+
"assignee",
|
|
147
|
+
"parent",
|
|
148
|
+
"blocked_by",
|
|
149
|
+
"blocked_reason",
|
|
150
|
+
"unblock_note",
|
|
151
|
+
"dependencies",
|
|
152
|
+
"comments",
|
|
153
|
+
"notes",
|
|
154
|
+
"learnings",
|
|
155
|
+
"files",
|
|
156
|
+
"tests",
|
|
157
|
+
"docs",
|
|
158
|
+
"reminders",
|
|
159
|
+
"events",
|
|
160
|
+
]);
|
|
10
161
|
function toAuthor(candidate, defaultAuthor) {
|
|
11
162
|
const resolved = candidate ?? process.env.PM_AUTHOR ?? defaultAuthor;
|
|
12
163
|
const trimmed = resolved.trim();
|
|
13
164
|
return trimmed || "unknown";
|
|
14
165
|
}
|
|
166
|
+
function isLegacyNoneToken(value) {
|
|
167
|
+
if (value === undefined) {
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return LEGACY_NONE_TOKENS.has(value.trim().toLowerCase());
|
|
171
|
+
}
|
|
172
|
+
function assertNoLegacyNoneToken(value, flag, replacementHint) {
|
|
173
|
+
if (!isLegacyNoneToken(value)) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const suffix = replacementHint ? ` ${replacementHint}` : "";
|
|
177
|
+
throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
|
|
178
|
+
}
|
|
179
|
+
function assertNoLegacyNoneTokens(values, flag, replacementHint) {
|
|
180
|
+
if (!values || values.length === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const hasLegacyToken = values.some((value) => isLegacyNoneToken(value));
|
|
184
|
+
if (!hasLegacyToken) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const suffix = replacementHint ? ` ${replacementHint}` : "";
|
|
188
|
+
throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
|
|
189
|
+
}
|
|
190
|
+
function resolveRuntimeUnsetDefinition(token, runtimeFieldRegistry) {
|
|
191
|
+
if (!runtimeFieldRegistry) {
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
for (const definition of runtimeFieldRegistry.definitions) {
|
|
195
|
+
if (definition.allow_unset === false) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const candidates = new Set([
|
|
199
|
+
definition.key,
|
|
200
|
+
definition.front_matter_key,
|
|
201
|
+
definition.cli_flag.replaceAll("-", "_"),
|
|
202
|
+
definition.cli_flag,
|
|
203
|
+
...definition.cli_aliases.map((alias) => alias.replaceAll("-", "_")),
|
|
204
|
+
...definition.cli_aliases,
|
|
205
|
+
]);
|
|
206
|
+
if (!candidates.has(token)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
optionKey: definition.key,
|
|
211
|
+
frontMatterKey: definition.front_matter_key,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
function parseUpdateUnsetTargets(raw, runtimeFieldRegistry) {
|
|
217
|
+
const frontMatterKeys = new Set();
|
|
218
|
+
const optionKeys = new Set();
|
|
219
|
+
if (!raw || raw.length === 0) {
|
|
220
|
+
return { frontMatterKeys, optionKeys };
|
|
221
|
+
}
|
|
222
|
+
for (const entry of raw) {
|
|
223
|
+
const trimmed = entry.trim().toLowerCase();
|
|
224
|
+
if (!trimmed) {
|
|
225
|
+
throw new PmCliError("--unset values must not be empty", EXIT_CODE.USAGE);
|
|
226
|
+
}
|
|
227
|
+
if (isLegacyNoneToken(trimmed)) {
|
|
228
|
+
throw new PmCliError('--unset no longer accepts "none" or "null". Specify concrete field names such as --unset deadline', EXIT_CODE.USAGE);
|
|
229
|
+
}
|
|
230
|
+
const definition = UPDATE_UNSET_ALIAS_MAP.get(trimmed) ?? resolveRuntimeUnsetDefinition(trimmed, runtimeFieldRegistry);
|
|
231
|
+
if (!definition) {
|
|
232
|
+
throw new PmCliError(`Unsupported --unset field "${entry}". Supported fields: ${UPDATE_UNSET_SUPPORTED_CANONICAL_FIELDS}`, EXIT_CODE.USAGE);
|
|
233
|
+
}
|
|
234
|
+
frontMatterKeys.add(definition.frontMatterKey);
|
|
235
|
+
optionKeys.add(definition.optionKey);
|
|
236
|
+
}
|
|
237
|
+
return { frontMatterKeys, optionKeys };
|
|
238
|
+
}
|
|
239
|
+
function enforceAllowAuditUpdateScope(options, clearFrontMatterKeys) {
|
|
240
|
+
const allowAuditUpdate = options.allowAuditUpdate === true;
|
|
241
|
+
const allowAuditDepUpdate = options.allowAuditDepUpdate === true;
|
|
242
|
+
if (!allowAuditUpdate && !allowAuditDepUpdate) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (allowAuditUpdate && allowAuditDepUpdate) {
|
|
246
|
+
throw new PmCliError("Choose either --allow-audit-update or --allow-audit-dep-update; these override modes are mutually exclusive.", EXIT_CODE.USAGE);
|
|
247
|
+
}
|
|
248
|
+
const pushIf = (condition, flag, list) => {
|
|
249
|
+
if (condition) {
|
|
250
|
+
list.push(flag);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
if (allowAuditDepUpdate) {
|
|
254
|
+
const disallowedFlags = [];
|
|
255
|
+
pushIf(options.title !== undefined, "--title", disallowedFlags);
|
|
256
|
+
pushIf(options.description !== undefined, "--description", disallowedFlags);
|
|
257
|
+
pushIf(options.body !== undefined, "--body", disallowedFlags);
|
|
258
|
+
pushIf(options.status !== undefined, "--status", disallowedFlags);
|
|
259
|
+
pushIf(options.closeReason !== undefined, "--close-reason", disallowedFlags);
|
|
260
|
+
pushIf(options.priority !== undefined, "--priority", disallowedFlags);
|
|
261
|
+
pushIf(options.type !== undefined, "--type", disallowedFlags);
|
|
262
|
+
pushIf(options.tags !== undefined, "--tags", disallowedFlags);
|
|
263
|
+
pushIf(options.deadline !== undefined, "--deadline", disallowedFlags);
|
|
264
|
+
pushIf(options.estimatedMinutes !== undefined, "--estimate", disallowedFlags);
|
|
265
|
+
pushIf(options.acceptanceCriteria !== undefined, "--acceptance-criteria", disallowedFlags);
|
|
266
|
+
pushIf(options.definitionOfReady !== undefined, "--definition-of-ready", disallowedFlags);
|
|
267
|
+
pushIf(options.order !== undefined || options.rank !== undefined, "--order/--rank", disallowedFlags);
|
|
268
|
+
pushIf(options.goal !== undefined, "--goal", disallowedFlags);
|
|
269
|
+
pushIf(options.objective !== undefined, "--objective", disallowedFlags);
|
|
270
|
+
pushIf(options.value !== undefined, "--value", disallowedFlags);
|
|
271
|
+
pushIf(options.impact !== undefined, "--impact", disallowedFlags);
|
|
272
|
+
pushIf(options.outcome !== undefined, "--outcome", disallowedFlags);
|
|
273
|
+
pushIf(options.whyNow !== undefined, "--why-now", disallowedFlags);
|
|
274
|
+
pushIf(options.assignee !== undefined, "--assignee", disallowedFlags);
|
|
275
|
+
pushIf(options.parent !== undefined, "--parent", disallowedFlags);
|
|
276
|
+
pushIf(options.reviewer !== undefined, "--reviewer", disallowedFlags);
|
|
277
|
+
pushIf(options.risk !== undefined, "--risk", disallowedFlags);
|
|
278
|
+
pushIf(options.confidence !== undefined, "--confidence", disallowedFlags);
|
|
279
|
+
pushIf(options.sprint !== undefined, "--sprint", disallowedFlags);
|
|
280
|
+
pushIf(options.release !== undefined, "--release", disallowedFlags);
|
|
281
|
+
pushIf(options.blockedBy !== undefined, "--blocked-by", disallowedFlags);
|
|
282
|
+
pushIf(options.blockedReason !== undefined, "--blocked-reason", disallowedFlags);
|
|
283
|
+
pushIf(options.unblockNote !== undefined, "--unblock-note", disallowedFlags);
|
|
284
|
+
pushIf(options.reporter !== undefined, "--reporter", disallowedFlags);
|
|
285
|
+
pushIf(options.severity !== undefined, "--severity", disallowedFlags);
|
|
286
|
+
pushIf(options.environment !== undefined, "--environment", disallowedFlags);
|
|
287
|
+
pushIf(options.reproSteps !== undefined, "--repro-steps", disallowedFlags);
|
|
288
|
+
pushIf(options.resolution !== undefined, "--resolution", disallowedFlags);
|
|
289
|
+
pushIf(options.expectedResult !== undefined, "--expected-result", disallowedFlags);
|
|
290
|
+
pushIf(options.actualResult !== undefined, "--actual-result", disallowedFlags);
|
|
291
|
+
pushIf(options.affectedVersion !== undefined, "--affected-version", disallowedFlags);
|
|
292
|
+
pushIf(options.fixedVersion !== undefined, "--fixed-version", disallowedFlags);
|
|
293
|
+
pushIf(options.component !== undefined, "--component", disallowedFlags);
|
|
294
|
+
pushIf(options.regression !== undefined, "--regression", disallowedFlags);
|
|
295
|
+
pushIf(options.customerImpact !== undefined, "--customer-impact", disallowedFlags);
|
|
296
|
+
pushIf(options.depRemove !== undefined, "--dep-remove", disallowedFlags);
|
|
297
|
+
pushIf(options.replaceDeps === true, "--replace-deps", disallowedFlags);
|
|
298
|
+
pushIf(options.replaceTests === true, "--replace-tests", disallowedFlags);
|
|
299
|
+
pushIf(options.comment !== undefined, "--comment", disallowedFlags);
|
|
300
|
+
pushIf(options.note !== undefined, "--note", disallowedFlags);
|
|
301
|
+
pushIf(options.learning !== undefined, "--learning", disallowedFlags);
|
|
302
|
+
pushIf(options.file !== undefined, "--file", disallowedFlags);
|
|
303
|
+
pushIf(options.test !== undefined, "--test", disallowedFlags);
|
|
304
|
+
pushIf(options.doc !== undefined, "--doc", disallowedFlags);
|
|
305
|
+
pushIf(options.reminder !== undefined, "--reminder", disallowedFlags);
|
|
306
|
+
pushIf(options.event !== undefined, "--event", disallowedFlags);
|
|
307
|
+
pushIf(options.typeOption !== undefined, "--type-option", disallowedFlags);
|
|
308
|
+
pushIf(options.clearDeps === true, "--clear-deps", disallowedFlags);
|
|
309
|
+
pushIf(options.clearComments === true, "--clear-comments", disallowedFlags);
|
|
310
|
+
pushIf(options.clearNotes === true, "--clear-notes", disallowedFlags);
|
|
311
|
+
pushIf(options.clearLearnings === true, "--clear-learnings", disallowedFlags);
|
|
312
|
+
pushIf(options.clearFiles === true, "--clear-files", disallowedFlags);
|
|
313
|
+
pushIf(options.clearTests === true, "--clear-tests", disallowedFlags);
|
|
314
|
+
pushIf(options.clearDocs === true, "--clear-docs", disallowedFlags);
|
|
315
|
+
pushIf(options.clearReminders === true, "--clear-reminders", disallowedFlags);
|
|
316
|
+
pushIf(options.clearEvents === true, "--clear-events", disallowedFlags);
|
|
317
|
+
pushIf(options.clearTypeOptions === true, "--clear-type-options", disallowedFlags);
|
|
318
|
+
pushIf(options.force === true, "--force", disallowedFlags);
|
|
319
|
+
pushIf(clearFrontMatterKeys.size > 0, "--unset", disallowedFlags);
|
|
320
|
+
if (options.dep === undefined || options.dep.length === 0) {
|
|
321
|
+
throw new PmCliError("--allow-audit-dep-update requires at least one --dep value", EXIT_CODE.USAGE);
|
|
322
|
+
}
|
|
323
|
+
if (disallowedFlags.length > 0) {
|
|
324
|
+
throw new PmCliError(`--allow-audit-dep-update supports append-only dependency additions via --dep. Remove restricted options: ${disallowedFlags.join(", ")}`, EXIT_CODE.USAGE);
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const disallowedFlags = [];
|
|
329
|
+
if (options.status !== undefined) {
|
|
330
|
+
disallowedFlags.push("--status");
|
|
331
|
+
}
|
|
332
|
+
if (options.closeReason !== undefined) {
|
|
333
|
+
disallowedFlags.push("--close-reason");
|
|
334
|
+
}
|
|
335
|
+
if (options.assignee !== undefined) {
|
|
336
|
+
disallowedFlags.push("--assignee");
|
|
337
|
+
}
|
|
338
|
+
if (options.parent !== undefined) {
|
|
339
|
+
disallowedFlags.push("--parent");
|
|
340
|
+
}
|
|
341
|
+
if (options.blockedBy !== undefined) {
|
|
342
|
+
disallowedFlags.push("--blocked-by");
|
|
343
|
+
}
|
|
344
|
+
if (options.blockedReason !== undefined) {
|
|
345
|
+
disallowedFlags.push("--blocked-reason");
|
|
346
|
+
}
|
|
347
|
+
if (options.unblockNote !== undefined) {
|
|
348
|
+
disallowedFlags.push("--unblock-note");
|
|
349
|
+
}
|
|
350
|
+
if (options.dep !== undefined) {
|
|
351
|
+
disallowedFlags.push("--dep");
|
|
352
|
+
}
|
|
353
|
+
if (options.depRemove !== undefined) {
|
|
354
|
+
disallowedFlags.push("--dep-remove");
|
|
355
|
+
}
|
|
356
|
+
if (options.replaceDeps === true) {
|
|
357
|
+
disallowedFlags.push("--replace-deps");
|
|
358
|
+
}
|
|
359
|
+
if (options.replaceTests === true) {
|
|
360
|
+
disallowedFlags.push("--replace-tests");
|
|
361
|
+
}
|
|
362
|
+
if (options.comment !== undefined) {
|
|
363
|
+
disallowedFlags.push("--comment");
|
|
364
|
+
}
|
|
365
|
+
if (options.note !== undefined) {
|
|
366
|
+
disallowedFlags.push("--note");
|
|
367
|
+
}
|
|
368
|
+
if (options.learning !== undefined) {
|
|
369
|
+
disallowedFlags.push("--learning");
|
|
370
|
+
}
|
|
371
|
+
if (options.file !== undefined) {
|
|
372
|
+
disallowedFlags.push("--file");
|
|
373
|
+
}
|
|
374
|
+
if (options.test !== undefined) {
|
|
375
|
+
disallowedFlags.push("--test");
|
|
376
|
+
}
|
|
377
|
+
if (options.doc !== undefined) {
|
|
378
|
+
disallowedFlags.push("--doc");
|
|
379
|
+
}
|
|
380
|
+
if (options.reminder !== undefined) {
|
|
381
|
+
disallowedFlags.push("--reminder");
|
|
382
|
+
}
|
|
383
|
+
if (options.event !== undefined) {
|
|
384
|
+
disallowedFlags.push("--event");
|
|
385
|
+
}
|
|
386
|
+
if (options.clearDeps === true) {
|
|
387
|
+
disallowedFlags.push("--clear-deps");
|
|
388
|
+
}
|
|
389
|
+
if (options.clearComments === true) {
|
|
390
|
+
disallowedFlags.push("--clear-comments");
|
|
391
|
+
}
|
|
392
|
+
if (options.clearNotes === true) {
|
|
393
|
+
disallowedFlags.push("--clear-notes");
|
|
394
|
+
}
|
|
395
|
+
if (options.clearLearnings === true) {
|
|
396
|
+
disallowedFlags.push("--clear-learnings");
|
|
397
|
+
}
|
|
398
|
+
if (options.clearFiles === true) {
|
|
399
|
+
disallowedFlags.push("--clear-files");
|
|
400
|
+
}
|
|
401
|
+
if (options.clearTests === true) {
|
|
402
|
+
disallowedFlags.push("--clear-tests");
|
|
403
|
+
}
|
|
404
|
+
if (options.clearDocs === true) {
|
|
405
|
+
disallowedFlags.push("--clear-docs");
|
|
406
|
+
}
|
|
407
|
+
if (options.clearReminders === true) {
|
|
408
|
+
disallowedFlags.push("--clear-reminders");
|
|
409
|
+
}
|
|
410
|
+
if (options.clearEvents === true) {
|
|
411
|
+
disallowedFlags.push("--clear-events");
|
|
412
|
+
}
|
|
413
|
+
const disallowedUnset = [...clearFrontMatterKeys]
|
|
414
|
+
.filter((field) => AUDIT_UPDATE_DISALLOWED_UNSET_FRONT_MATTER_KEYS.has(field))
|
|
415
|
+
.sort((left, right) => left.localeCompare(right))
|
|
416
|
+
.map((field) => `--unset ${field.replaceAll("_", "-")}`);
|
|
417
|
+
disallowedFlags.push(...disallowedUnset);
|
|
418
|
+
if (disallowedFlags.length > 0) {
|
|
419
|
+
throw new PmCliError(`--allow-audit-update only supports non-lifecycle metadata fields. Remove restricted options: ${disallowedFlags.join(", ")}`, EXIT_CODE.USAGE);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
15
422
|
function ensureEnum(value, allowed, label) {
|
|
16
423
|
if (!allowed.includes(value)) {
|
|
17
424
|
throw new PmCliError(`Invalid ${label} value "${value}"`, EXIT_CODE.USAGE);
|
|
18
425
|
}
|
|
19
426
|
return value;
|
|
20
427
|
}
|
|
428
|
+
function parseStatus(value, statusRegistry) {
|
|
429
|
+
const normalized = normalizeStatusInput(value, statusRegistry);
|
|
430
|
+
if (!normalized) {
|
|
431
|
+
const allowedStatuses = statusRegistry.definitions.map((definition) => definition.id);
|
|
432
|
+
throw new PmCliError(`Invalid --status value "${value}". Allowed: ${allowedStatuses.join(", ")}`, EXIT_CODE.USAGE);
|
|
433
|
+
}
|
|
434
|
+
return normalized;
|
|
435
|
+
}
|
|
21
436
|
function normalizeRiskInput(value) {
|
|
22
437
|
const trimmed = value.trim();
|
|
23
438
|
return trimmed.toLowerCase() === "med" ? "medium" : trimmed;
|
|
@@ -50,6 +465,278 @@ function parseRegressionInput(value) {
|
|
|
50
465
|
}
|
|
51
466
|
throw new PmCliError("Regression must be one of true|false|1|0", EXIT_CODE.USAGE);
|
|
52
467
|
}
|
|
468
|
+
function weekdayOrderIndex(value) {
|
|
469
|
+
return RECURRENCE_WEEKDAY_VALUES.indexOf(value);
|
|
470
|
+
}
|
|
471
|
+
function parseReminderEntries(raw, nowValue) {
|
|
472
|
+
return raw.map((entry) => {
|
|
473
|
+
const kv = parseCsvKv(entry, "--reminder");
|
|
474
|
+
const atRaw = kv.at?.trim();
|
|
475
|
+
const textRaw = kv.text?.trim();
|
|
476
|
+
if (!atRaw || !textRaw) {
|
|
477
|
+
throw new PmCliError("--reminder requires at=<iso|relative> and text=<value>", EXIT_CODE.USAGE);
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
at: resolveIsoOrRelative(atRaw, nowValue, "reminder.at"),
|
|
481
|
+
text: textRaw,
|
|
482
|
+
};
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
function parseEventBoolean(value, flag) {
|
|
486
|
+
const normalized = value.trim().toLowerCase();
|
|
487
|
+
if (normalized === "true" || normalized === "1" || normalized === "yes") {
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
if (normalized === "false" || normalized === "0" || normalized === "no") {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
throw new PmCliError(`${flag} must be one of true|false|1|0|yes|no`, EXIT_CODE.USAGE);
|
|
494
|
+
}
|
|
495
|
+
function parseDelimitedList(raw) {
|
|
496
|
+
if (!raw) {
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
return raw
|
|
500
|
+
.split("|")
|
|
501
|
+
.map((value) => value.trim())
|
|
502
|
+
.filter((value) => value.length > 0);
|
|
503
|
+
}
|
|
504
|
+
function parseRecurrenceRule(kv, startAt, nowValue) {
|
|
505
|
+
const freqRaw = kv.recur_freq?.trim();
|
|
506
|
+
const intervalRaw = kv.recur_interval?.trim();
|
|
507
|
+
const countRaw = kv.recur_count?.trim();
|
|
508
|
+
const untilRaw = kv.recur_until?.trim();
|
|
509
|
+
const byWeekdayRaw = kv.recur_by_weekday?.trim();
|
|
510
|
+
const byMonthDayRaw = kv.recur_by_month_day?.trim();
|
|
511
|
+
const exdatesRaw = kv.recur_exdates?.trim();
|
|
512
|
+
const recurrenceInputsProvided = [freqRaw, intervalRaw, countRaw, untilRaw, byWeekdayRaw, byMonthDayRaw, exdatesRaw].some((value) => value !== undefined);
|
|
513
|
+
if (!recurrenceInputsProvided) {
|
|
514
|
+
return undefined;
|
|
515
|
+
}
|
|
516
|
+
if (!freqRaw) {
|
|
517
|
+
throw new PmCliError("--event recurrence fields require recur_freq=<daily|weekly|monthly|yearly>", EXIT_CODE.USAGE);
|
|
518
|
+
}
|
|
519
|
+
const freq = ensureEnum(freqRaw.toLowerCase(), RECURRENCE_FREQUENCY_VALUES, "event recurrence frequency");
|
|
520
|
+
const interval = intervalRaw ? parseOptionalNumber(intervalRaw, "event recur_interval") : undefined;
|
|
521
|
+
if (interval !== undefined && (!Number.isInteger(interval) || interval < 1)) {
|
|
522
|
+
throw new PmCliError("--event recur_interval must be an integer >= 1", EXIT_CODE.USAGE);
|
|
523
|
+
}
|
|
524
|
+
const count = countRaw ? parseOptionalNumber(countRaw, "event recur_count") : undefined;
|
|
525
|
+
if (count !== undefined && (!Number.isInteger(count) || count < 1)) {
|
|
526
|
+
throw new PmCliError("--event recur_count must be an integer >= 1", EXIT_CODE.USAGE);
|
|
527
|
+
}
|
|
528
|
+
const until = untilRaw ? resolveIsoOrRelative(untilRaw, nowValue, "event.recur_until") : undefined;
|
|
529
|
+
if (until && until < startAt) {
|
|
530
|
+
throw new PmCliError("--event recur_until must be at or after start", EXIT_CODE.USAGE);
|
|
531
|
+
}
|
|
532
|
+
const byWeekday = Array.from(new Set(parseDelimitedList(byWeekdayRaw)
|
|
533
|
+
.map((value) => ensureEnum(value.toLowerCase(), RECURRENCE_WEEKDAY_VALUES, "event weekday")))).sort((left, right) => weekdayOrderIndex(left) -
|
|
534
|
+
weekdayOrderIndex(right));
|
|
535
|
+
const byMonthDay = Array.from(new Set(parseDelimitedList(byMonthDayRaw)
|
|
536
|
+
.map((value) => {
|
|
537
|
+
const day = parseOptionalNumber(value, "event recur_by_month_day");
|
|
538
|
+
if (!Number.isInteger(day) || day < 1 || day > 31) {
|
|
539
|
+
throw new PmCliError("--event recur_by_month_day values must be integers 1..31", EXIT_CODE.USAGE);
|
|
540
|
+
}
|
|
541
|
+
return day;
|
|
542
|
+
}))).sort((left, right) => left - right);
|
|
543
|
+
const exdates = Array.from(new Set(parseDelimitedList(exdatesRaw).map((value) => resolveIsoOrRelative(value, nowValue, "event.recur_exdates")))).sort((left, right) => left.localeCompare(right));
|
|
544
|
+
return {
|
|
545
|
+
freq,
|
|
546
|
+
interval,
|
|
547
|
+
count,
|
|
548
|
+
until,
|
|
549
|
+
by_weekday: byWeekday.length > 0 ? byWeekday : undefined,
|
|
550
|
+
by_month_day: byMonthDay.length > 0 ? byMonthDay : undefined,
|
|
551
|
+
exdates: exdates.length > 0 ? exdates : undefined,
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
function parseEventEntries(raw, nowValue) {
|
|
555
|
+
return raw.map((entry) => {
|
|
556
|
+
const kv = parseCsvKv(entry, "--event");
|
|
557
|
+
const startRaw = kv.start?.trim();
|
|
558
|
+
if (!startRaw) {
|
|
559
|
+
throw new PmCliError("--event requires start=<iso|relative>", EXIT_CODE.USAGE);
|
|
560
|
+
}
|
|
561
|
+
const startAt = resolveIsoOrRelative(startRaw, nowValue, "event.start");
|
|
562
|
+
const endRaw = kv.end?.trim();
|
|
563
|
+
const endAt = endRaw ? resolveIsoOrRelative(endRaw, nowValue, "event.end") : undefined;
|
|
564
|
+
if (endAt && endAt <= startAt) {
|
|
565
|
+
throw new PmCliError("--event end must be after start", EXIT_CODE.USAGE);
|
|
566
|
+
}
|
|
567
|
+
const titleRaw = kv.title;
|
|
568
|
+
const descriptionRaw = kv.description;
|
|
569
|
+
const locationRaw = kv.location;
|
|
570
|
+
const timezoneRaw = kv.timezone;
|
|
571
|
+
const title = titleRaw?.trim();
|
|
572
|
+
const description = descriptionRaw?.trim();
|
|
573
|
+
const location = locationRaw?.trim();
|
|
574
|
+
const timezone = timezoneRaw?.trim();
|
|
575
|
+
if (titleRaw !== undefined && !title) {
|
|
576
|
+
throw new PmCliError("--event title must not be empty", EXIT_CODE.USAGE);
|
|
577
|
+
}
|
|
578
|
+
if (descriptionRaw !== undefined && !description) {
|
|
579
|
+
throw new PmCliError("--event description must not be empty", EXIT_CODE.USAGE);
|
|
580
|
+
}
|
|
581
|
+
if (locationRaw !== undefined && !location) {
|
|
582
|
+
throw new PmCliError("--event location must not be empty", EXIT_CODE.USAGE);
|
|
583
|
+
}
|
|
584
|
+
if (timezoneRaw !== undefined && !timezone) {
|
|
585
|
+
throw new PmCliError("--event timezone must not be empty", EXIT_CODE.USAGE);
|
|
586
|
+
}
|
|
587
|
+
const allDayRaw = kv.all_day?.trim();
|
|
588
|
+
const recurrence = parseRecurrenceRule(kv, startAt, nowValue);
|
|
589
|
+
return {
|
|
590
|
+
start_at: startAt,
|
|
591
|
+
end_at: endAt,
|
|
592
|
+
title,
|
|
593
|
+
description,
|
|
594
|
+
location,
|
|
595
|
+
all_day: allDayRaw ? parseEventBoolean(allDayRaw, "--event all_day") : undefined,
|
|
596
|
+
timezone,
|
|
597
|
+
recurrence,
|
|
598
|
+
};
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
function parseTypeOptionEntries(raw) {
|
|
602
|
+
const values = {};
|
|
603
|
+
for (const entry of raw) {
|
|
604
|
+
const trimmedEntry = entry.trim();
|
|
605
|
+
if (trimmedEntry.length === 0) {
|
|
606
|
+
throw new PmCliError("--type-option values must not be empty", EXIT_CODE.USAGE);
|
|
607
|
+
}
|
|
608
|
+
let key;
|
|
609
|
+
let value;
|
|
610
|
+
const prefersStructuredKv = trimmedEntry.includes(",") ||
|
|
611
|
+
trimmedEntry.includes("\n") ||
|
|
612
|
+
trimmedEntry.startsWith("```") ||
|
|
613
|
+
/^(?:[-*+]\s+)?(?:key|value)\s*[:=]/i.test(trimmedEntry);
|
|
614
|
+
if (prefersStructuredKv) {
|
|
615
|
+
const kv = parseCsvKv(trimmedEntry, "--type-option");
|
|
616
|
+
key = kv.key?.trim();
|
|
617
|
+
value = kv.value?.trim();
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
const equalsIndex = trimmedEntry.indexOf("=");
|
|
621
|
+
const colonIndex = trimmedEntry.indexOf(":");
|
|
622
|
+
let separatorIndex = equalsIndex;
|
|
623
|
+
if (equalsIndex <= 0 && colonIndex > 0) {
|
|
624
|
+
separatorIndex = colonIndex;
|
|
625
|
+
}
|
|
626
|
+
if (separatorIndex <= 0 || separatorIndex === trimmedEntry.length - 1) {
|
|
627
|
+
throw new PmCliError("--type-option requires key=value or key=<name>,value=<value> entries", EXIT_CODE.USAGE);
|
|
628
|
+
}
|
|
629
|
+
key = trimmedEntry.slice(0, separatorIndex).trim();
|
|
630
|
+
value = trimmedEntry.slice(separatorIndex + 1).trim();
|
|
631
|
+
}
|
|
632
|
+
if (!key || !value) {
|
|
633
|
+
throw new PmCliError("--type-option requires key and value", EXIT_CODE.USAGE);
|
|
634
|
+
}
|
|
635
|
+
values[key] = value;
|
|
636
|
+
}
|
|
637
|
+
return Object.fromEntries(Object.entries(values).sort((left, right) => left[0].localeCompare(right[0])));
|
|
638
|
+
}
|
|
639
|
+
function parseDependencyCreatedAt(value, currentIso) {
|
|
640
|
+
if (!value || value.trim() === "" || value.trim().toLowerCase() === "now") {
|
|
641
|
+
return currentIso;
|
|
642
|
+
}
|
|
643
|
+
const parsed = Date.parse(value);
|
|
644
|
+
if (!Number.isFinite(parsed)) {
|
|
645
|
+
throw new PmCliError(`Invalid dependency created_at timestamp "${value}"`, EXIT_CODE.USAGE);
|
|
646
|
+
}
|
|
647
|
+
return new Date(parsed).toISOString();
|
|
648
|
+
}
|
|
649
|
+
function parseOptionalDependencyString(value) {
|
|
650
|
+
if (value === undefined)
|
|
651
|
+
return undefined;
|
|
652
|
+
const trimmed = value.trim();
|
|
653
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
654
|
+
}
|
|
655
|
+
function parseDependencyAdditions(raw, prefix, nowIso) {
|
|
656
|
+
if (!raw) {
|
|
657
|
+
return { additions: [] };
|
|
658
|
+
}
|
|
659
|
+
assertNoLegacyNoneTokens(raw, "--dep", "Use --clear-deps to clear dependencies.");
|
|
660
|
+
const additions = raw.map((entry) => {
|
|
661
|
+
const kv = parseCsvKv(entry, "--dep");
|
|
662
|
+
const id = kv.id?.trim();
|
|
663
|
+
const kind = kv.kind?.trim();
|
|
664
|
+
if (!id || !kind) {
|
|
665
|
+
throw new PmCliError("--dep requires id and kind", EXIT_CODE.USAGE);
|
|
666
|
+
}
|
|
667
|
+
if (id.toLowerCase() === "undefined") {
|
|
668
|
+
throw new PmCliError(`--dep id must not use placeholder token "${id}". Use --clear-deps to clear dependencies.`, EXIT_CODE.USAGE);
|
|
669
|
+
}
|
|
670
|
+
const sourceKind = parseOptionalDependencyString(kv.source_kind);
|
|
671
|
+
return {
|
|
672
|
+
id: normalizeItemId(id, prefix),
|
|
673
|
+
kind: ensureEnum(kind, DEPENDENCY_KIND_VALUES, "dependency kind"),
|
|
674
|
+
created_at: parseDependencyCreatedAt(kv.created_at, nowIso),
|
|
675
|
+
author: parseOptionalDependencyString(kv.author),
|
|
676
|
+
source_kind: sourceKind,
|
|
677
|
+
};
|
|
678
|
+
});
|
|
679
|
+
return { additions };
|
|
680
|
+
}
|
|
681
|
+
function parseDependencyRemovals(raw, prefix) {
|
|
682
|
+
if (!raw) {
|
|
683
|
+
return [];
|
|
684
|
+
}
|
|
685
|
+
assertNoLegacyNoneTokens(raw, "--dep-remove");
|
|
686
|
+
return raw.map((entry) => {
|
|
687
|
+
const trimmed = entry.trim();
|
|
688
|
+
if (!trimmed) {
|
|
689
|
+
throw new PmCliError("--dep-remove requires id or key/value selectors", EXIT_CODE.USAGE);
|
|
690
|
+
}
|
|
691
|
+
if (trimmed.includes("=") || /^(?:[-*+]\s+)?(?:id|kind|source_kind)\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
|
|
692
|
+
const kv = parseCsvKv(trimmed, "--dep-remove");
|
|
693
|
+
const idRaw = kv.id?.trim();
|
|
694
|
+
if (!idRaw) {
|
|
695
|
+
throw new PmCliError("--dep-remove key/value form requires id=<value>", EXIT_CODE.USAGE);
|
|
696
|
+
}
|
|
697
|
+
if (idRaw.toLowerCase() === "undefined") {
|
|
698
|
+
throw new PmCliError(`--dep-remove id must not use placeholder token "${idRaw}"`, EXIT_CODE.USAGE);
|
|
699
|
+
}
|
|
700
|
+
const kindRaw = parseOptionalDependencyString(kv.kind);
|
|
701
|
+
const sourceKind = parseOptionalDependencyString(kv.source_kind);
|
|
702
|
+
return {
|
|
703
|
+
id: normalizeItemId(idRaw, prefix),
|
|
704
|
+
kind: kindRaw ? ensureEnum(kindRaw, DEPENDENCY_KIND_VALUES, "dependency kind") : undefined,
|
|
705
|
+
source_kind: sourceKind,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
if (trimmed.toLowerCase() === "undefined") {
|
|
709
|
+
throw new PmCliError(`--dep-remove id must not use placeholder token "${trimmed}"`, EXIT_CODE.USAGE);
|
|
710
|
+
}
|
|
711
|
+
return {
|
|
712
|
+
id: normalizeItemId(trimmed, prefix),
|
|
713
|
+
};
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function dependencyKey(value) {
|
|
717
|
+
return `${value.id}::${value.kind}::${value.source_kind ?? ""}`;
|
|
718
|
+
}
|
|
719
|
+
function fileKey(value) {
|
|
720
|
+
return `${value.path}::${value.scope}`;
|
|
721
|
+
}
|
|
722
|
+
function docKey(value) {
|
|
723
|
+
return `${value.path}::${value.scope}`;
|
|
724
|
+
}
|
|
725
|
+
function testKey(value) {
|
|
726
|
+
return `${value.command}::${value.path ?? ""}::${value.scope}::${value.pm_context_mode ?? ""}`;
|
|
727
|
+
}
|
|
728
|
+
function matchesDependencySelector(value, selector) {
|
|
729
|
+
if (value.id !== selector.id) {
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
if (selector.kind && value.kind !== selector.kind) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
if (selector.source_kind !== undefined && (value.source_kind ?? undefined) !== selector.source_kind) {
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
53
740
|
function ensurePriority(raw) {
|
|
54
741
|
const parsed = parseOptionalNumber(raw, "priority");
|
|
55
742
|
if (![0, 1, 2, 3, 4].includes(parsed)) {
|
|
@@ -57,17 +744,368 @@ function ensurePriority(raw) {
|
|
|
57
744
|
}
|
|
58
745
|
return parsed;
|
|
59
746
|
}
|
|
747
|
+
function normalizeUpdatePolicyOptionKey(raw, typeName) {
|
|
748
|
+
const canonical = canonicalizeCommandOptionKey("update", raw);
|
|
749
|
+
if (!canonical) {
|
|
750
|
+
throw new PmCliError(`Unsupported command_option_policies option "${raw}" for update command on type "${typeName}"`, EXIT_CODE.CONFLICT);
|
|
751
|
+
}
|
|
752
|
+
return canonical;
|
|
753
|
+
}
|
|
754
|
+
function collectProvidedUpdatePolicyOptions(options) {
|
|
755
|
+
const provided = new Set();
|
|
756
|
+
const mark = (optionKey, isProvided) => {
|
|
757
|
+
if (isProvided) {
|
|
758
|
+
provided.add(optionKey);
|
|
759
|
+
}
|
|
760
|
+
};
|
|
761
|
+
mark("title", options.title !== undefined);
|
|
762
|
+
mark("description", options.description !== undefined);
|
|
763
|
+
mark("body", options.body !== undefined);
|
|
764
|
+
mark("status", options.status !== undefined);
|
|
765
|
+
mark("closeReason", options.closeReason !== undefined);
|
|
766
|
+
mark("priority", options.priority !== undefined);
|
|
767
|
+
mark("type", options.type !== undefined);
|
|
768
|
+
mark("tags", options.tags !== undefined);
|
|
769
|
+
mark("deadline", options.deadline !== undefined);
|
|
770
|
+
mark("estimatedMinutes", options.estimatedMinutes !== undefined);
|
|
771
|
+
mark("acceptanceCriteria", options.acceptanceCriteria !== undefined);
|
|
772
|
+
mark("definitionOfReady", options.definitionOfReady !== undefined);
|
|
773
|
+
mark("order", options.order !== undefined || options.rank !== undefined);
|
|
774
|
+
mark("goal", options.goal !== undefined);
|
|
775
|
+
mark("objective", options.objective !== undefined);
|
|
776
|
+
mark("value", options.value !== undefined);
|
|
777
|
+
mark("impact", options.impact !== undefined);
|
|
778
|
+
mark("outcome", options.outcome !== undefined);
|
|
779
|
+
mark("whyNow", options.whyNow !== undefined);
|
|
780
|
+
mark("author", options.author !== undefined);
|
|
781
|
+
mark("message", options.message !== undefined);
|
|
782
|
+
mark("assignee", options.assignee !== undefined);
|
|
783
|
+
mark("parent", options.parent !== undefined);
|
|
784
|
+
mark("reviewer", options.reviewer !== undefined);
|
|
785
|
+
mark("risk", options.risk !== undefined);
|
|
786
|
+
mark("confidence", options.confidence !== undefined);
|
|
787
|
+
mark("sprint", options.sprint !== undefined);
|
|
788
|
+
mark("release", options.release !== undefined);
|
|
789
|
+
mark("blockedBy", options.blockedBy !== undefined);
|
|
790
|
+
mark("blockedReason", options.blockedReason !== undefined);
|
|
791
|
+
mark("unblockNote", options.unblockNote !== undefined);
|
|
792
|
+
mark("reporter", options.reporter !== undefined);
|
|
793
|
+
mark("severity", options.severity !== undefined);
|
|
794
|
+
mark("environment", options.environment !== undefined);
|
|
795
|
+
mark("reproSteps", options.reproSteps !== undefined);
|
|
796
|
+
mark("resolution", options.resolution !== undefined);
|
|
797
|
+
mark("expectedResult", options.expectedResult !== undefined);
|
|
798
|
+
mark("actualResult", options.actualResult !== undefined);
|
|
799
|
+
mark("affectedVersion", options.affectedVersion !== undefined);
|
|
800
|
+
mark("fixedVersion", options.fixedVersion !== undefined);
|
|
801
|
+
mark("component", options.component !== undefined);
|
|
802
|
+
mark("regression", options.regression !== undefined);
|
|
803
|
+
mark("customerImpact", options.customerImpact !== undefined);
|
|
804
|
+
mark("dep", options.dep !== undefined);
|
|
805
|
+
mark("depRemove", options.depRemove !== undefined);
|
|
806
|
+
mark("dep", options.replaceDeps === true);
|
|
807
|
+
mark("comment", options.comment !== undefined);
|
|
808
|
+
mark("note", options.note !== undefined);
|
|
809
|
+
mark("learning", options.learning !== undefined);
|
|
810
|
+
mark("file", options.file !== undefined);
|
|
811
|
+
mark("test", options.test !== undefined);
|
|
812
|
+
mark("test", options.replaceTests === true);
|
|
813
|
+
mark("doc", options.doc !== undefined);
|
|
814
|
+
mark("reminder", options.reminder !== undefined);
|
|
815
|
+
mark("event", options.event !== undefined);
|
|
816
|
+
mark("typeOption", options.typeOption !== undefined);
|
|
817
|
+
mark("force", options.force === true);
|
|
818
|
+
mark("allowAuditUpdate", options.allowAuditUpdate === true);
|
|
819
|
+
mark("dep", options.clearDeps === true);
|
|
820
|
+
mark("comment", options.clearComments === true);
|
|
821
|
+
mark("note", options.clearNotes === true);
|
|
822
|
+
mark("learning", options.clearLearnings === true);
|
|
823
|
+
mark("file", options.clearFiles === true);
|
|
824
|
+
mark("test", options.clearTests === true);
|
|
825
|
+
mark("doc", options.clearDocs === true);
|
|
826
|
+
mark("reminder", options.clearReminders === true);
|
|
827
|
+
mark("event", options.clearEvents === true);
|
|
828
|
+
mark("typeOption", options.clearTypeOptions === true);
|
|
829
|
+
if (options.unset && options.unset.length > 0) {
|
|
830
|
+
const unsetTargets = parseUpdateUnsetTargets(options.unset);
|
|
831
|
+
for (const optionKey of unsetTargets.optionKeys) {
|
|
832
|
+
mark(optionKey, true);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return provided;
|
|
836
|
+
}
|
|
837
|
+
function enforceUpdateOptionsByType(typeName, options, typeRegistry) {
|
|
838
|
+
const typeDefinition = resolveTypeDefinition(typeName, typeRegistry);
|
|
839
|
+
if (!typeDefinition) {
|
|
840
|
+
throw new PmCliError(`Invalid type value "${typeName}"`, EXIT_CODE.USAGE);
|
|
841
|
+
}
|
|
842
|
+
const policyState = resolveCommandOptionPolicyState(typeDefinition, "update", []);
|
|
843
|
+
if (policyState.errors.length > 0) {
|
|
844
|
+
throw new PmCliError(policyState.errors.join("; "), EXIT_CODE.CONFLICT);
|
|
845
|
+
}
|
|
846
|
+
const provided = collectProvidedUpdatePolicyOptions(options);
|
|
847
|
+
for (const disabled of policyState.disabled) {
|
|
848
|
+
if (provided.has(normalizeUpdatePolicyOptionKey(disabled, typeName))) {
|
|
849
|
+
throw new PmCliError(`Option ${commandOptionFlagLabel("update", disabled)} is disabled for type "${typeName}" by command_option_policies`, EXIT_CODE.USAGE);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
for (const required of policyState.required) {
|
|
853
|
+
if (!provided.has(normalizeUpdatePolicyOptionKey(required, typeName))) {
|
|
854
|
+
throw new PmCliError(`Missing required option ${commandOptionFlagLabel("update", required)} for type "${typeName}"`, EXIT_CODE.USAGE);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
60
858
|
export async function runUpdate(id, options, global) {
|
|
859
|
+
const stdinResolver = createStdinTokenResolver();
|
|
860
|
+
options = {
|
|
861
|
+
...options,
|
|
862
|
+
body: await stdinResolver.resolveValue(options.body, "--body"),
|
|
863
|
+
dep: await stdinResolver.resolveList(options.dep, "--dep"),
|
|
864
|
+
depRemove: await stdinResolver.resolveList(options.depRemove, "--dep-remove"),
|
|
865
|
+
comment: await stdinResolver.resolveList(options.comment, "--comment"),
|
|
866
|
+
note: await stdinResolver.resolveList(options.note, "--note"),
|
|
867
|
+
learning: await stdinResolver.resolveList(options.learning, "--learning"),
|
|
868
|
+
file: await stdinResolver.resolveList(options.file, "--file"),
|
|
869
|
+
test: await stdinResolver.resolveList(options.test, "--test"),
|
|
870
|
+
doc: await stdinResolver.resolveList(options.doc, "--doc"),
|
|
871
|
+
reminder: await stdinResolver.resolveList(options.reminder, "--reminder"),
|
|
872
|
+
event: await stdinResolver.resolveList(options.event, "--event"),
|
|
873
|
+
typeOption: await stdinResolver.resolveList(options.typeOption, "--type-option"),
|
|
874
|
+
};
|
|
61
875
|
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
62
876
|
if (!(await pathExists(getSettingsPath(pmRoot)))) {
|
|
63
877
|
throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
|
|
64
878
|
}
|
|
65
879
|
const settings = await readSettings(pmRoot);
|
|
880
|
+
const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
|
|
881
|
+
const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
|
|
882
|
+
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
883
|
+
const parentReferencePolicy = settings.validation.parent_reference;
|
|
884
|
+
const sprintReleasePolicy = settings.validation.sprint_release_format;
|
|
885
|
+
const unsetTargets = parseUpdateUnsetTargets(options.unset, runtimeFieldRegistry);
|
|
886
|
+
const clearOptionKeys = new Set(unsetTargets.optionKeys);
|
|
887
|
+
const clearFrontMatterKeys = new Set(unsetTargets.frontMatterKeys);
|
|
888
|
+
const clearCollectionDefinitions = [
|
|
889
|
+
{
|
|
890
|
+
enabled: options.clearDeps || options.replaceDeps,
|
|
891
|
+
optionKey: "dep",
|
|
892
|
+
clearFlag: "--clear-deps",
|
|
893
|
+
valueFlag: "--dep",
|
|
894
|
+
values: options.dep,
|
|
895
|
+
frontMatterKey: "dependencies",
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
enabled: options.clearComments,
|
|
899
|
+
optionKey: "comment",
|
|
900
|
+
clearFlag: "--clear-comments",
|
|
901
|
+
valueFlag: "--comment",
|
|
902
|
+
values: options.comment,
|
|
903
|
+
frontMatterKey: "comments",
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
enabled: options.clearNotes,
|
|
907
|
+
optionKey: "note",
|
|
908
|
+
clearFlag: "--clear-notes",
|
|
909
|
+
valueFlag: "--note",
|
|
910
|
+
values: options.note,
|
|
911
|
+
frontMatterKey: "notes",
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
enabled: options.clearLearnings,
|
|
915
|
+
optionKey: "learning",
|
|
916
|
+
clearFlag: "--clear-learnings",
|
|
917
|
+
valueFlag: "--learning",
|
|
918
|
+
values: options.learning,
|
|
919
|
+
frontMatterKey: "learnings",
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
enabled: options.clearFiles,
|
|
923
|
+
optionKey: "file",
|
|
924
|
+
clearFlag: "--clear-files",
|
|
925
|
+
valueFlag: "--file",
|
|
926
|
+
values: options.file,
|
|
927
|
+
frontMatterKey: "files",
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
enabled: options.clearTests || options.replaceTests,
|
|
931
|
+
optionKey: "test",
|
|
932
|
+
clearFlag: "--clear-tests",
|
|
933
|
+
valueFlag: "--test",
|
|
934
|
+
values: options.test,
|
|
935
|
+
frontMatterKey: "tests",
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
enabled: options.clearDocs,
|
|
939
|
+
optionKey: "doc",
|
|
940
|
+
clearFlag: "--clear-docs",
|
|
941
|
+
valueFlag: "--doc",
|
|
942
|
+
values: options.doc,
|
|
943
|
+
frontMatterKey: "docs",
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
enabled: options.clearReminders,
|
|
947
|
+
optionKey: "reminder",
|
|
948
|
+
clearFlag: "--clear-reminders",
|
|
949
|
+
valueFlag: "--reminder",
|
|
950
|
+
values: options.reminder,
|
|
951
|
+
frontMatterKey: "reminders",
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
enabled: options.clearEvents,
|
|
955
|
+
optionKey: "event",
|
|
956
|
+
clearFlag: "--clear-events",
|
|
957
|
+
valueFlag: "--event",
|
|
958
|
+
values: options.event,
|
|
959
|
+
frontMatterKey: "events",
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
enabled: options.clearTypeOptions,
|
|
963
|
+
optionKey: "typeOption",
|
|
964
|
+
clearFlag: "--clear-type-options",
|
|
965
|
+
valueFlag: "--type-option",
|
|
966
|
+
values: options.typeOption,
|
|
967
|
+
frontMatterKey: "type_options",
|
|
968
|
+
},
|
|
969
|
+
];
|
|
970
|
+
if (options.replaceDeps === true && (options.dep === undefined || options.dep.length === 0)) {
|
|
971
|
+
throw new PmCliError("--replace-deps requires at least one --dep entry", EXIT_CODE.USAGE);
|
|
972
|
+
}
|
|
973
|
+
if (options.replaceDeps === true && options.depRemove !== undefined && options.depRemove.length > 0) {
|
|
974
|
+
throw new PmCliError("--replace-deps cannot be combined with --dep-remove", EXIT_CODE.USAGE);
|
|
975
|
+
}
|
|
976
|
+
if (options.replaceTests === true && (options.test === undefined || options.test.length === 0)) {
|
|
977
|
+
throw new PmCliError("--replace-tests requires at least one --test entry", EXIT_CODE.USAGE);
|
|
978
|
+
}
|
|
979
|
+
if (options.replaceTests === true && options.clearTests === true) {
|
|
980
|
+
throw new PmCliError("--replace-tests cannot be combined with --clear-tests", EXIT_CODE.USAGE);
|
|
981
|
+
}
|
|
982
|
+
for (const definition of clearCollectionDefinitions) {
|
|
983
|
+
if (!definition.enabled) {
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
if (definition.values &&
|
|
987
|
+
definition.values.length > 0 &&
|
|
988
|
+
!((definition.optionKey === "dep" && options.replaceDeps === true) ||
|
|
989
|
+
(definition.optionKey === "test" && options.replaceTests === true))) {
|
|
990
|
+
throw new PmCliError(`Cannot combine ${definition.clearFlag} with ${definition.valueFlag}`, EXIT_CODE.USAGE);
|
|
991
|
+
}
|
|
992
|
+
clearOptionKeys.add(definition.optionKey);
|
|
993
|
+
clearFrontMatterKeys.add(definition.frontMatterKey);
|
|
994
|
+
}
|
|
995
|
+
enforceAllowAuditUpdateScope(options, clearFrontMatterKeys);
|
|
996
|
+
const scalarOptionPresence = {
|
|
997
|
+
tags: options.tags !== undefined,
|
|
998
|
+
closeReason: options.closeReason !== undefined,
|
|
999
|
+
deadline: options.deadline !== undefined,
|
|
1000
|
+
estimatedMinutes: options.estimatedMinutes !== undefined,
|
|
1001
|
+
acceptanceCriteria: options.acceptanceCriteria !== undefined,
|
|
1002
|
+
definitionOfReady: options.definitionOfReady !== undefined,
|
|
1003
|
+
order: options.order !== undefined || options.rank !== undefined,
|
|
1004
|
+
goal: options.goal !== undefined,
|
|
1005
|
+
objective: options.objective !== undefined,
|
|
1006
|
+
value: options.value !== undefined,
|
|
1007
|
+
impact: options.impact !== undefined,
|
|
1008
|
+
outcome: options.outcome !== undefined,
|
|
1009
|
+
whyNow: options.whyNow !== undefined,
|
|
1010
|
+
assignee: options.assignee !== undefined,
|
|
1011
|
+
parent: options.parent !== undefined,
|
|
1012
|
+
reviewer: options.reviewer !== undefined,
|
|
1013
|
+
risk: options.risk !== undefined,
|
|
1014
|
+
confidence: options.confidence !== undefined,
|
|
1015
|
+
sprint: options.sprint !== undefined,
|
|
1016
|
+
release: options.release !== undefined,
|
|
1017
|
+
blockedBy: options.blockedBy !== undefined,
|
|
1018
|
+
blockedReason: options.blockedReason !== undefined,
|
|
1019
|
+
unblockNote: options.unblockNote !== undefined,
|
|
1020
|
+
reporter: options.reporter !== undefined,
|
|
1021
|
+
severity: options.severity !== undefined,
|
|
1022
|
+
environment: options.environment !== undefined,
|
|
1023
|
+
reproSteps: options.reproSteps !== undefined,
|
|
1024
|
+
resolution: options.resolution !== undefined,
|
|
1025
|
+
expectedResult: options.expectedResult !== undefined,
|
|
1026
|
+
actualResult: options.actualResult !== undefined,
|
|
1027
|
+
affectedVersion: options.affectedVersion !== undefined,
|
|
1028
|
+
fixedVersion: options.fixedVersion !== undefined,
|
|
1029
|
+
component: options.component !== undefined,
|
|
1030
|
+
regression: options.regression !== undefined,
|
|
1031
|
+
customerImpact: options.customerImpact !== undefined,
|
|
1032
|
+
};
|
|
1033
|
+
for (const [optionKey, hasValue] of Object.entries(scalarOptionPresence)) {
|
|
1034
|
+
if (!hasValue || !unsetTargets.optionKeys.has(optionKey)) {
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
const unsetField = UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.get(optionKey) ?? optionKey;
|
|
1038
|
+
throw new PmCliError(`Cannot combine --unset ${unsetField} with ${commandOptionFlagLabel("update", optionKey)}`, EXIT_CODE.USAGE);
|
|
1039
|
+
}
|
|
1040
|
+
const assertNoLegacyScalarToken = (value, optionKey) => {
|
|
1041
|
+
const unsetField = UPDATE_OPTION_KEY_TO_UNSET_CANONICAL.get(optionKey);
|
|
1042
|
+
const hint = unsetField ? `Use --unset ${unsetField} to clear this field.` : undefined;
|
|
1043
|
+
assertNoLegacyNoneToken(value, commandOptionFlagLabel("update", optionKey), hint);
|
|
1044
|
+
};
|
|
1045
|
+
assertNoLegacyScalarToken(options.tags, "tags");
|
|
1046
|
+
assertNoLegacyScalarToken(options.closeReason, "closeReason");
|
|
1047
|
+
assertNoLegacyScalarToken(options.deadline, "deadline");
|
|
1048
|
+
assertNoLegacyScalarToken(options.estimatedMinutes, "estimatedMinutes");
|
|
1049
|
+
assertNoLegacyScalarToken(options.acceptanceCriteria, "acceptanceCriteria");
|
|
1050
|
+
assertNoLegacyScalarToken(options.definitionOfReady, "definitionOfReady");
|
|
1051
|
+
assertNoLegacyScalarToken(options.order ?? options.rank, "order");
|
|
1052
|
+
assertNoLegacyScalarToken(options.goal, "goal");
|
|
1053
|
+
assertNoLegacyScalarToken(options.objective, "objective");
|
|
1054
|
+
assertNoLegacyScalarToken(options.value, "value");
|
|
1055
|
+
assertNoLegacyScalarToken(options.impact, "impact");
|
|
1056
|
+
assertNoLegacyScalarToken(options.outcome, "outcome");
|
|
1057
|
+
assertNoLegacyScalarToken(options.whyNow, "whyNow");
|
|
1058
|
+
assertNoLegacyScalarToken(options.assignee, "assignee");
|
|
1059
|
+
assertNoLegacyScalarToken(options.parent, "parent");
|
|
1060
|
+
assertNoLegacyScalarToken(options.reviewer, "reviewer");
|
|
1061
|
+
assertNoLegacyScalarToken(options.risk, "risk");
|
|
1062
|
+
assertNoLegacyScalarToken(options.confidence, "confidence");
|
|
1063
|
+
assertNoLegacyScalarToken(options.sprint, "sprint");
|
|
1064
|
+
assertNoLegacyScalarToken(options.release, "release");
|
|
1065
|
+
assertNoLegacyScalarToken(options.blockedBy, "blockedBy");
|
|
1066
|
+
assertNoLegacyScalarToken(options.blockedReason, "blockedReason");
|
|
1067
|
+
assertNoLegacyScalarToken(options.unblockNote, "unblockNote");
|
|
1068
|
+
assertNoLegacyScalarToken(options.reporter, "reporter");
|
|
1069
|
+
assertNoLegacyScalarToken(options.severity, "severity");
|
|
1070
|
+
assertNoLegacyScalarToken(options.environment, "environment");
|
|
1071
|
+
assertNoLegacyScalarToken(options.reproSteps, "reproSteps");
|
|
1072
|
+
assertNoLegacyScalarToken(options.resolution, "resolution");
|
|
1073
|
+
assertNoLegacyScalarToken(options.expectedResult, "expectedResult");
|
|
1074
|
+
assertNoLegacyScalarToken(options.actualResult, "actualResult");
|
|
1075
|
+
assertNoLegacyScalarToken(options.affectedVersion, "affectedVersion");
|
|
1076
|
+
assertNoLegacyScalarToken(options.fixedVersion, "fixedVersion");
|
|
1077
|
+
assertNoLegacyScalarToken(options.component, "component");
|
|
1078
|
+
assertNoLegacyScalarToken(options.regression, "regression");
|
|
1079
|
+
assertNoLegacyScalarToken(options.customerImpact, "customerImpact");
|
|
1080
|
+
assertNoLegacyNoneTokens(options.reminder, "--reminder", "Use --clear-reminders to clear reminders.");
|
|
1081
|
+
assertNoLegacyNoneTokens(options.event, "--event", "Use --clear-events to clear linked events.");
|
|
66
1082
|
const author = toAuthor(options.author, settings.author_default);
|
|
1083
|
+
const nowValue = new Date();
|
|
1084
|
+
const nowIso = nowValue.toISOString();
|
|
1085
|
+
const dependencyUpdates = parseDependencyAdditions(options.dep, settings.id_prefix, nowIso);
|
|
1086
|
+
const dependencyRemovals = parseDependencyRemovals(options.depRemove, settings.id_prefix);
|
|
1087
|
+
const commentUpdates = parseLogSeed("--comment", options.comment, nowIso, author);
|
|
1088
|
+
const noteUpdates = parseLogSeed("--note", options.note, nowIso, author);
|
|
1089
|
+
const learningUpdates = parseLogSeed("--learning", options.learning, nowIso, author);
|
|
1090
|
+
const fileUpdates = parseFiles(options.file);
|
|
1091
|
+
const testUpdates = parseTests(options.test);
|
|
1092
|
+
const docUpdates = parseDocs(options.doc);
|
|
1093
|
+
const parentReferenceWarnings = [];
|
|
1094
|
+
let resolvedParentValue;
|
|
1095
|
+
if (options.parent !== undefined && !unsetTargets.frontMatterKeys.has("parent")) {
|
|
1096
|
+
resolvedParentValue = normalizeParentReferenceValue(options.parent);
|
|
1097
|
+
const parentLocated = await locateItem(pmRoot, resolvedParentValue, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
|
|
1098
|
+
if (!parentLocated) {
|
|
1099
|
+
const normalizedParentId = normalizeItemId(resolvedParentValue, settings.id_prefix);
|
|
1100
|
+
parentReferenceWarnings.push(...validateMissingParentReference(normalizedParentId, parentReferencePolicy).warnings);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
67
1103
|
const changedFlags = [
|
|
68
1104
|
options.title !== undefined,
|
|
69
1105
|
options.description !== undefined,
|
|
1106
|
+
options.body !== undefined,
|
|
70
1107
|
options.status !== undefined,
|
|
1108
|
+
options.closeReason !== undefined,
|
|
71
1109
|
options.priority !== undefined,
|
|
72
1110
|
options.type !== undefined,
|
|
73
1111
|
options.tags !== undefined,
|
|
@@ -105,6 +1143,30 @@ export async function runUpdate(id, options, global) {
|
|
|
105
1143
|
options.component !== undefined,
|
|
106
1144
|
options.regression !== undefined,
|
|
107
1145
|
options.customerImpact !== undefined,
|
|
1146
|
+
options.dep !== undefined,
|
|
1147
|
+
options.depRemove !== undefined,
|
|
1148
|
+
options.replaceDeps === true,
|
|
1149
|
+
options.comment !== undefined,
|
|
1150
|
+
options.note !== undefined,
|
|
1151
|
+
options.learning !== undefined,
|
|
1152
|
+
options.file !== undefined,
|
|
1153
|
+
options.test !== undefined,
|
|
1154
|
+
options.replaceTests === true,
|
|
1155
|
+
options.doc !== undefined,
|
|
1156
|
+
options.reminder !== undefined,
|
|
1157
|
+
options.event !== undefined,
|
|
1158
|
+
options.typeOption !== undefined,
|
|
1159
|
+
options.unset !== undefined && options.unset.length > 0,
|
|
1160
|
+
options.clearDeps === true,
|
|
1161
|
+
options.clearComments === true,
|
|
1162
|
+
options.clearNotes === true,
|
|
1163
|
+
options.clearLearnings === true,
|
|
1164
|
+
options.clearFiles === true,
|
|
1165
|
+
options.clearTests === true,
|
|
1166
|
+
options.clearDocs === true,
|
|
1167
|
+
options.clearReminders === true,
|
|
1168
|
+
options.clearEvents === true,
|
|
1169
|
+
options.clearTypeOptions === true,
|
|
108
1170
|
].some(Boolean);
|
|
109
1171
|
if (!changedFlags) {
|
|
110
1172
|
throw new PmCliError("No update flags provided", EXIT_CODE.USAGE);
|
|
@@ -115,13 +1177,17 @@ export async function runUpdate(id, options, global) {
|
|
|
115
1177
|
const result = await mutateItem({
|
|
116
1178
|
pmRoot,
|
|
117
1179
|
settings,
|
|
1180
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
118
1181
|
id,
|
|
119
|
-
op: "update",
|
|
1182
|
+
op: options.allowAuditUpdate === true || options.allowAuditDepUpdate === true ? "update_audit" : "update",
|
|
120
1183
|
author,
|
|
121
1184
|
message: options.message,
|
|
122
1185
|
force: options.force,
|
|
1186
|
+
bypassAssigneeConflict: options.allowAuditUpdate === true || options.allowAuditDepUpdate === true,
|
|
123
1187
|
mutate(document) {
|
|
124
1188
|
const changedFields = [];
|
|
1189
|
+
const warnings = [];
|
|
1190
|
+
let activeTypeName = resolveTypeName(document.front_matter.type, typeRegistry) ?? document.front_matter.type;
|
|
125
1191
|
if (options.title !== undefined) {
|
|
126
1192
|
document.front_matter.title = options.title;
|
|
127
1193
|
changedFields.push("title");
|
|
@@ -130,40 +1196,230 @@ export async function runUpdate(id, options, global) {
|
|
|
130
1196
|
document.front_matter.description = options.description;
|
|
131
1197
|
changedFields.push("description");
|
|
132
1198
|
}
|
|
1199
|
+
if (options.body !== undefined) {
|
|
1200
|
+
document.body = options.body;
|
|
1201
|
+
changedFields.push("body");
|
|
1202
|
+
}
|
|
1203
|
+
const previousStatus = document.front_matter.status;
|
|
1204
|
+
const previousStatusNormalized = normalizeStatusInput(previousStatus, statusRegistry) ?? previousStatus;
|
|
133
1205
|
if (options.status !== undefined) {
|
|
134
|
-
const status =
|
|
135
|
-
if (status ===
|
|
136
|
-
throw new PmCliError(
|
|
1206
|
+
const status = parseStatus(options.status, statusRegistry);
|
|
1207
|
+
if (status === statusRegistry.close_status) {
|
|
1208
|
+
throw new PmCliError(`Invalid --status value "${statusRegistry.close_status}". Use "pm close <ID> <TEXT>" to close an item.`, EXIT_CODE.USAGE, {
|
|
1209
|
+
code: "close_through_update",
|
|
1210
|
+
why: "Closing requires a close reason and optional validation checks that pm update cannot enforce. Use pm close for auditable close workflows.",
|
|
1211
|
+
examples: [
|
|
1212
|
+
`pm close ${id} "All acceptance criteria met" --author "${author}" --message "Close: verified"`,
|
|
1213
|
+
`pm close ${id} "Resolved" --validate-close warn --author "${author}"`,
|
|
1214
|
+
],
|
|
1215
|
+
nextSteps: [
|
|
1216
|
+
'Use "pm close <ID> <reason>" to close with required close reason and optional --validate-close.',
|
|
1217
|
+
'To cancel instead, use "pm update <ID> --status canceled".',
|
|
1218
|
+
],
|
|
1219
|
+
});
|
|
137
1220
|
}
|
|
138
1221
|
document.front_matter.status = status;
|
|
139
|
-
if (status ===
|
|
1222
|
+
if (status === statusRegistry.canceled_status) {
|
|
140
1223
|
delete document.front_matter.assignee;
|
|
141
1224
|
}
|
|
142
1225
|
changedFields.push("status");
|
|
143
1226
|
}
|
|
1227
|
+
if (options.closeReason !== undefined || clearFrontMatterKeys.has("close_reason")) {
|
|
1228
|
+
if (clearFrontMatterKeys.has("close_reason")) {
|
|
1229
|
+
delete document.front_matter.close_reason;
|
|
1230
|
+
}
|
|
1231
|
+
else {
|
|
1232
|
+
const closeReason = options.closeReason.trim();
|
|
1233
|
+
if (closeReason.length === 0) {
|
|
1234
|
+
throw new PmCliError("--close-reason must not be empty", EXIT_CODE.USAGE);
|
|
1235
|
+
}
|
|
1236
|
+
document.front_matter.close_reason = closeReason;
|
|
1237
|
+
}
|
|
1238
|
+
changedFields.push("close_reason");
|
|
1239
|
+
}
|
|
1240
|
+
else if (options.status !== undefined &&
|
|
1241
|
+
previousStatusNormalized === statusRegistry.close_status &&
|
|
1242
|
+
document.front_matter.status !== statusRegistry.canceled_status &&
|
|
1243
|
+
document.front_matter.close_reason !== undefined) {
|
|
1244
|
+
delete document.front_matter.close_reason;
|
|
1245
|
+
changedFields.push("close_reason");
|
|
1246
|
+
}
|
|
144
1247
|
if (options.priority !== undefined) {
|
|
145
1248
|
document.front_matter.priority = ensurePriority(options.priority);
|
|
146
1249
|
changedFields.push("priority");
|
|
147
1250
|
}
|
|
148
1251
|
if (options.type !== undefined) {
|
|
149
|
-
|
|
1252
|
+
const resolvedTypeName = resolveTypeName(options.type, typeRegistry);
|
|
1253
|
+
if (!resolvedTypeName) {
|
|
1254
|
+
throw new PmCliError(`Invalid type value "${options.type}". Allowed: ${typeRegistry.types.join(", ")}`, EXIT_CODE.USAGE);
|
|
1255
|
+
}
|
|
1256
|
+
document.front_matter.type = resolvedTypeName;
|
|
1257
|
+
activeTypeName = resolvedTypeName;
|
|
150
1258
|
changedFields.push("type");
|
|
151
1259
|
}
|
|
152
|
-
|
|
153
|
-
|
|
1260
|
+
enforceUpdateOptionsByType(activeTypeName, options, typeRegistry);
|
|
1261
|
+
if (options.typeOption !== undefined || clearFrontMatterKeys.has("type_options")) {
|
|
1262
|
+
if (clearFrontMatterKeys.has("type_options")) {
|
|
1263
|
+
delete document.front_matter.type_options;
|
|
1264
|
+
}
|
|
1265
|
+
else {
|
|
1266
|
+
const parsedTypeOptions = parseTypeOptionEntries(options.typeOption);
|
|
1267
|
+
const validation = validateTypeOptions(activeTypeName, parsedTypeOptions, typeRegistry);
|
|
1268
|
+
if (validation.errors.length > 0) {
|
|
1269
|
+
throw new PmCliError(validation.errors.join("; "), EXIT_CODE.USAGE);
|
|
1270
|
+
}
|
|
1271
|
+
document.front_matter.type_options = validation.normalized;
|
|
1272
|
+
}
|
|
1273
|
+
changedFields.push("type_options");
|
|
1274
|
+
}
|
|
1275
|
+
else if (options.type !== undefined && document.front_matter.type_options !== undefined) {
|
|
1276
|
+
const validation = validateTypeOptions(activeTypeName, document.front_matter.type_options, typeRegistry);
|
|
1277
|
+
if (validation.errors.length > 0) {
|
|
1278
|
+
throw new PmCliError(`Current type options are incompatible with type "${activeTypeName}". ${validation.errors.join("; ")}. Use --clear-type-options to clear them.`, EXIT_CODE.USAGE);
|
|
1279
|
+
}
|
|
1280
|
+
document.front_matter.type_options = validation.normalized;
|
|
1281
|
+
}
|
|
1282
|
+
if (options.dep !== undefined || options.depRemove !== undefined || clearFrontMatterKeys.has("dependencies")) {
|
|
1283
|
+
let nextDependencies = clearFrontMatterKeys.has("dependencies") ? [] : [...(document.front_matter.dependencies ?? [])];
|
|
1284
|
+
if (dependencyUpdates.additions.length > 0) {
|
|
1285
|
+
const seen = new Set(nextDependencies.map((entry) => dependencyKey(entry)));
|
|
1286
|
+
for (const addition of dependencyUpdates.additions) {
|
|
1287
|
+
const key = dependencyKey(addition);
|
|
1288
|
+
if (seen.has(key)) {
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
nextDependencies.push(addition);
|
|
1292
|
+
seen.add(key);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
if (dependencyRemovals.length > 0) {
|
|
1296
|
+
nextDependencies = nextDependencies.filter((entry) => !dependencyRemovals.some((selector) => matchesDependencySelector(entry, selector)));
|
|
1297
|
+
}
|
|
1298
|
+
if (nextDependencies.length === 0) {
|
|
1299
|
+
delete document.front_matter.dependencies;
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
document.front_matter.dependencies = nextDependencies;
|
|
1303
|
+
}
|
|
1304
|
+
changedFields.push("dependencies");
|
|
1305
|
+
}
|
|
1306
|
+
if (options.comment !== undefined || clearFrontMatterKeys.has("comments")) {
|
|
1307
|
+
if (clearFrontMatterKeys.has("comments") || !commentUpdates.values || commentUpdates.values.length === 0) {
|
|
1308
|
+
delete document.front_matter.comments;
|
|
1309
|
+
}
|
|
1310
|
+
else {
|
|
1311
|
+
document.front_matter.comments = [...(document.front_matter.comments ?? []), ...commentUpdates.values];
|
|
1312
|
+
}
|
|
1313
|
+
changedFields.push("comments");
|
|
1314
|
+
}
|
|
1315
|
+
if (options.note !== undefined || clearFrontMatterKeys.has("notes")) {
|
|
1316
|
+
if (clearFrontMatterKeys.has("notes") || !noteUpdates.values || noteUpdates.values.length === 0) {
|
|
1317
|
+
delete document.front_matter.notes;
|
|
1318
|
+
}
|
|
1319
|
+
else {
|
|
1320
|
+
document.front_matter.notes = [...(document.front_matter.notes ?? []), ...noteUpdates.values];
|
|
1321
|
+
}
|
|
1322
|
+
changedFields.push("notes");
|
|
1323
|
+
}
|
|
1324
|
+
if (options.learning !== undefined || clearFrontMatterKeys.has("learnings")) {
|
|
1325
|
+
if (clearFrontMatterKeys.has("learnings") || !learningUpdates.values || learningUpdates.values.length === 0) {
|
|
1326
|
+
delete document.front_matter.learnings;
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
document.front_matter.learnings = [...(document.front_matter.learnings ?? []), ...learningUpdates.values];
|
|
1330
|
+
}
|
|
1331
|
+
changedFields.push("learnings");
|
|
1332
|
+
}
|
|
1333
|
+
if (options.file !== undefined || clearFrontMatterKeys.has("files")) {
|
|
1334
|
+
if (clearFrontMatterKeys.has("files") || !fileUpdates.values || fileUpdates.values.length === 0) {
|
|
1335
|
+
delete document.front_matter.files;
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
const nextFiles = [...(document.front_matter.files ?? [])];
|
|
1339
|
+
const seen = new Set(nextFiles.map((entry) => fileKey(entry)));
|
|
1340
|
+
for (const entry of fileUpdates.values) {
|
|
1341
|
+
const key = fileKey(entry);
|
|
1342
|
+
if (seen.has(key)) {
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
nextFiles.push(entry);
|
|
1346
|
+
seen.add(key);
|
|
1347
|
+
}
|
|
1348
|
+
document.front_matter.files = nextFiles;
|
|
1349
|
+
}
|
|
1350
|
+
changedFields.push("files");
|
|
1351
|
+
}
|
|
1352
|
+
if (options.test !== undefined || clearFrontMatterKeys.has("tests")) {
|
|
1353
|
+
if (clearFrontMatterKeys.has("tests") && options.replaceTests === true) {
|
|
1354
|
+
if (!testUpdates.values || testUpdates.values.length === 0) {
|
|
1355
|
+
delete document.front_matter.tests;
|
|
1356
|
+
}
|
|
1357
|
+
else {
|
|
1358
|
+
const replacementTests = [];
|
|
1359
|
+
const seen = new Set();
|
|
1360
|
+
for (const entry of testUpdates.values) {
|
|
1361
|
+
const key = testKey(entry);
|
|
1362
|
+
if (seen.has(key)) {
|
|
1363
|
+
continue;
|
|
1364
|
+
}
|
|
1365
|
+
replacementTests.push(entry);
|
|
1366
|
+
seen.add(key);
|
|
1367
|
+
}
|
|
1368
|
+
document.front_matter.tests = replacementTests;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
else if (clearFrontMatterKeys.has("tests") || !testUpdates.values || testUpdates.values.length === 0) {
|
|
1372
|
+
delete document.front_matter.tests;
|
|
1373
|
+
}
|
|
1374
|
+
else {
|
|
1375
|
+
const nextTests = [...(document.front_matter.tests ?? [])];
|
|
1376
|
+
const seen = new Set(nextTests.map((entry) => testKey(entry)));
|
|
1377
|
+
for (const entry of testUpdates.values) {
|
|
1378
|
+
const key = testKey(entry);
|
|
1379
|
+
if (seen.has(key)) {
|
|
1380
|
+
continue;
|
|
1381
|
+
}
|
|
1382
|
+
nextTests.push(entry);
|
|
1383
|
+
seen.add(key);
|
|
1384
|
+
}
|
|
1385
|
+
document.front_matter.tests = nextTests;
|
|
1386
|
+
}
|
|
1387
|
+
changedFields.push("tests");
|
|
1388
|
+
}
|
|
1389
|
+
if (options.doc !== undefined || clearFrontMatterKeys.has("docs")) {
|
|
1390
|
+
if (clearFrontMatterKeys.has("docs") || !docUpdates.values || docUpdates.values.length === 0) {
|
|
1391
|
+
delete document.front_matter.docs;
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
const nextDocs = [...(document.front_matter.docs ?? [])];
|
|
1395
|
+
const seen = new Set(nextDocs.map((entry) => docKey(entry)));
|
|
1396
|
+
for (const entry of docUpdates.values) {
|
|
1397
|
+
const key = docKey(entry);
|
|
1398
|
+
if (seen.has(key)) {
|
|
1399
|
+
continue;
|
|
1400
|
+
}
|
|
1401
|
+
nextDocs.push(entry);
|
|
1402
|
+
seen.add(key);
|
|
1403
|
+
}
|
|
1404
|
+
document.front_matter.docs = nextDocs;
|
|
1405
|
+
}
|
|
1406
|
+
changedFields.push("docs");
|
|
1407
|
+
}
|
|
1408
|
+
if (options.tags !== undefined || clearFrontMatterKeys.has("tags")) {
|
|
1409
|
+
document.front_matter.tags = clearFrontMatterKeys.has("tags") ? [] : parseTags(options.tags);
|
|
154
1410
|
changedFields.push("tags");
|
|
155
1411
|
}
|
|
156
|
-
if (options.deadline !== undefined) {
|
|
157
|
-
if (
|
|
1412
|
+
if (options.deadline !== undefined || clearFrontMatterKeys.has("deadline")) {
|
|
1413
|
+
if (clearFrontMatterKeys.has("deadline")) {
|
|
158
1414
|
delete document.front_matter.deadline;
|
|
159
1415
|
}
|
|
160
1416
|
else {
|
|
161
|
-
document.front_matter.deadline = resolveIsoOrRelative(options.deadline);
|
|
1417
|
+
document.front_matter.deadline = resolveIsoOrRelative(options.deadline, new Date(), "deadline");
|
|
162
1418
|
}
|
|
163
1419
|
changedFields.push("deadline");
|
|
164
1420
|
}
|
|
165
|
-
if (options.estimatedMinutes !== undefined) {
|
|
166
|
-
if (
|
|
1421
|
+
if (options.estimatedMinutes !== undefined || clearFrontMatterKeys.has("estimated_minutes")) {
|
|
1422
|
+
if (clearFrontMatterKeys.has("estimated_minutes")) {
|
|
167
1423
|
delete document.front_matter.estimated_minutes;
|
|
168
1424
|
}
|
|
169
1425
|
else {
|
|
@@ -171,8 +1427,8 @@ export async function runUpdate(id, options, global) {
|
|
|
171
1427
|
}
|
|
172
1428
|
changedFields.push("estimated_minutes");
|
|
173
1429
|
}
|
|
174
|
-
if (options.acceptanceCriteria !== undefined) {
|
|
175
|
-
if (
|
|
1430
|
+
if (options.acceptanceCriteria !== undefined || clearFrontMatterKeys.has("acceptance_criteria")) {
|
|
1431
|
+
if (clearFrontMatterKeys.has("acceptance_criteria")) {
|
|
176
1432
|
delete document.front_matter.acceptance_criteria;
|
|
177
1433
|
}
|
|
178
1434
|
else {
|
|
@@ -180,8 +1436,8 @@ export async function runUpdate(id, options, global) {
|
|
|
180
1436
|
}
|
|
181
1437
|
changedFields.push("acceptance_criteria");
|
|
182
1438
|
}
|
|
183
|
-
if (options.definitionOfReady !== undefined) {
|
|
184
|
-
if (
|
|
1439
|
+
if (options.definitionOfReady !== undefined || clearFrontMatterKeys.has("definition_of_ready")) {
|
|
1440
|
+
if (clearFrontMatterKeys.has("definition_of_ready")) {
|
|
185
1441
|
delete document.front_matter.definition_of_ready;
|
|
186
1442
|
}
|
|
187
1443
|
else {
|
|
@@ -190,8 +1446,8 @@ export async function runUpdate(id, options, global) {
|
|
|
190
1446
|
changedFields.push("definition_of_ready");
|
|
191
1447
|
}
|
|
192
1448
|
const orderRaw = options.order ?? options.rank;
|
|
193
|
-
if (orderRaw !== undefined) {
|
|
194
|
-
if (
|
|
1449
|
+
if (orderRaw !== undefined || clearFrontMatterKeys.has("order")) {
|
|
1450
|
+
if (clearFrontMatterKeys.has("order")) {
|
|
195
1451
|
delete document.front_matter.order;
|
|
196
1452
|
}
|
|
197
1453
|
else {
|
|
@@ -203,8 +1459,8 @@ export async function runUpdate(id, options, global) {
|
|
|
203
1459
|
}
|
|
204
1460
|
changedFields.push("order");
|
|
205
1461
|
}
|
|
206
|
-
if (options.goal !== undefined) {
|
|
207
|
-
if (
|
|
1462
|
+
if (options.goal !== undefined || clearFrontMatterKeys.has("goal")) {
|
|
1463
|
+
if (clearFrontMatterKeys.has("goal")) {
|
|
208
1464
|
delete document.front_matter.goal;
|
|
209
1465
|
}
|
|
210
1466
|
else {
|
|
@@ -212,8 +1468,8 @@ export async function runUpdate(id, options, global) {
|
|
|
212
1468
|
}
|
|
213
1469
|
changedFields.push("goal");
|
|
214
1470
|
}
|
|
215
|
-
if (options.objective !== undefined) {
|
|
216
|
-
if (
|
|
1471
|
+
if (options.objective !== undefined || clearFrontMatterKeys.has("objective")) {
|
|
1472
|
+
if (clearFrontMatterKeys.has("objective")) {
|
|
217
1473
|
delete document.front_matter.objective;
|
|
218
1474
|
}
|
|
219
1475
|
else {
|
|
@@ -221,8 +1477,8 @@ export async function runUpdate(id, options, global) {
|
|
|
221
1477
|
}
|
|
222
1478
|
changedFields.push("objective");
|
|
223
1479
|
}
|
|
224
|
-
if (options.value !== undefined) {
|
|
225
|
-
if (
|
|
1480
|
+
if (options.value !== undefined || clearFrontMatterKeys.has("value")) {
|
|
1481
|
+
if (clearFrontMatterKeys.has("value")) {
|
|
226
1482
|
delete document.front_matter.value;
|
|
227
1483
|
}
|
|
228
1484
|
else {
|
|
@@ -230,8 +1486,8 @@ export async function runUpdate(id, options, global) {
|
|
|
230
1486
|
}
|
|
231
1487
|
changedFields.push("value");
|
|
232
1488
|
}
|
|
233
|
-
if (options.impact !== undefined) {
|
|
234
|
-
if (
|
|
1489
|
+
if (options.impact !== undefined || clearFrontMatterKeys.has("impact")) {
|
|
1490
|
+
if (clearFrontMatterKeys.has("impact")) {
|
|
235
1491
|
delete document.front_matter.impact;
|
|
236
1492
|
}
|
|
237
1493
|
else {
|
|
@@ -239,8 +1495,8 @@ export async function runUpdate(id, options, global) {
|
|
|
239
1495
|
}
|
|
240
1496
|
changedFields.push("impact");
|
|
241
1497
|
}
|
|
242
|
-
if (options.outcome !== undefined) {
|
|
243
|
-
if (
|
|
1498
|
+
if (options.outcome !== undefined || clearFrontMatterKeys.has("outcome")) {
|
|
1499
|
+
if (clearFrontMatterKeys.has("outcome")) {
|
|
244
1500
|
delete document.front_matter.outcome;
|
|
245
1501
|
}
|
|
246
1502
|
else {
|
|
@@ -248,8 +1504,8 @@ export async function runUpdate(id, options, global) {
|
|
|
248
1504
|
}
|
|
249
1505
|
changedFields.push("outcome");
|
|
250
1506
|
}
|
|
251
|
-
if (options.whyNow !== undefined) {
|
|
252
|
-
if (
|
|
1507
|
+
if (options.whyNow !== undefined || clearFrontMatterKeys.has("why_now")) {
|
|
1508
|
+
if (clearFrontMatterKeys.has("why_now")) {
|
|
253
1509
|
delete document.front_matter.why_now;
|
|
254
1510
|
}
|
|
255
1511
|
else {
|
|
@@ -257,26 +1513,29 @@ export async function runUpdate(id, options, global) {
|
|
|
257
1513
|
}
|
|
258
1514
|
changedFields.push("why_now");
|
|
259
1515
|
}
|
|
260
|
-
if (options.assignee !== undefined) {
|
|
261
|
-
if (
|
|
1516
|
+
if (options.assignee !== undefined || clearFrontMatterKeys.has("assignee")) {
|
|
1517
|
+
if (clearFrontMatterKeys.has("assignee")) {
|
|
262
1518
|
delete document.front_matter.assignee;
|
|
263
1519
|
}
|
|
264
1520
|
else {
|
|
1521
|
+
if (options.assignee.trim() === "") {
|
|
1522
|
+
throw new PmCliError("--assignee must not be empty. Use --unset assignee to clear it.", EXIT_CODE.USAGE);
|
|
1523
|
+
}
|
|
265
1524
|
document.front_matter.assignee = options.assignee.trim();
|
|
266
1525
|
}
|
|
267
1526
|
changedFields.push("assignee");
|
|
268
1527
|
}
|
|
269
|
-
if (options.parent !== undefined) {
|
|
270
|
-
if (
|
|
1528
|
+
if (options.parent !== undefined || clearFrontMatterKeys.has("parent")) {
|
|
1529
|
+
if (clearFrontMatterKeys.has("parent")) {
|
|
271
1530
|
delete document.front_matter.parent;
|
|
272
1531
|
}
|
|
273
1532
|
else {
|
|
274
|
-
document.front_matter.parent =
|
|
1533
|
+
document.front_matter.parent = resolvedParentValue;
|
|
275
1534
|
}
|
|
276
1535
|
changedFields.push("parent");
|
|
277
1536
|
}
|
|
278
|
-
if (options.reviewer !== undefined) {
|
|
279
|
-
if (
|
|
1537
|
+
if (options.reviewer !== undefined || clearFrontMatterKeys.has("reviewer")) {
|
|
1538
|
+
if (clearFrontMatterKeys.has("reviewer")) {
|
|
280
1539
|
delete document.front_matter.reviewer;
|
|
281
1540
|
}
|
|
282
1541
|
else {
|
|
@@ -284,8 +1543,8 @@ export async function runUpdate(id, options, global) {
|
|
|
284
1543
|
}
|
|
285
1544
|
changedFields.push("reviewer");
|
|
286
1545
|
}
|
|
287
|
-
if (options.risk !== undefined) {
|
|
288
|
-
if (
|
|
1546
|
+
if (options.risk !== undefined || clearFrontMatterKeys.has("risk")) {
|
|
1547
|
+
if (clearFrontMatterKeys.has("risk")) {
|
|
289
1548
|
delete document.front_matter.risk;
|
|
290
1549
|
}
|
|
291
1550
|
else {
|
|
@@ -293,8 +1552,8 @@ export async function runUpdate(id, options, global) {
|
|
|
293
1552
|
}
|
|
294
1553
|
changedFields.push("risk");
|
|
295
1554
|
}
|
|
296
|
-
if (options.confidence !== undefined) {
|
|
297
|
-
if (
|
|
1555
|
+
if (options.confidence !== undefined || clearFrontMatterKeys.has("confidence")) {
|
|
1556
|
+
if (clearFrontMatterKeys.has("confidence")) {
|
|
298
1557
|
delete document.front_matter.confidence;
|
|
299
1558
|
}
|
|
300
1559
|
else {
|
|
@@ -302,26 +1561,30 @@ export async function runUpdate(id, options, global) {
|
|
|
302
1561
|
}
|
|
303
1562
|
changedFields.push("confidence");
|
|
304
1563
|
}
|
|
305
|
-
if (options.sprint !== undefined) {
|
|
306
|
-
if (
|
|
1564
|
+
if (options.sprint !== undefined || clearFrontMatterKeys.has("sprint")) {
|
|
1565
|
+
if (clearFrontMatterKeys.has("sprint")) {
|
|
307
1566
|
delete document.front_matter.sprint;
|
|
308
1567
|
}
|
|
309
1568
|
else {
|
|
310
|
-
|
|
1569
|
+
const sprintValidation = validateSprintOrReleaseValue("sprint", options.sprint, sprintReleasePolicy);
|
|
1570
|
+
document.front_matter.sprint = sprintValidation.value;
|
|
1571
|
+
warnings.push(...sprintValidation.warnings);
|
|
311
1572
|
}
|
|
312
1573
|
changedFields.push("sprint");
|
|
313
1574
|
}
|
|
314
|
-
if (options.release !== undefined) {
|
|
315
|
-
if (
|
|
1575
|
+
if (options.release !== undefined || clearFrontMatterKeys.has("release")) {
|
|
1576
|
+
if (clearFrontMatterKeys.has("release")) {
|
|
316
1577
|
delete document.front_matter.release;
|
|
317
1578
|
}
|
|
318
1579
|
else {
|
|
319
|
-
|
|
1580
|
+
const releaseValidation = validateSprintOrReleaseValue("release", options.release, sprintReleasePolicy);
|
|
1581
|
+
document.front_matter.release = releaseValidation.value;
|
|
1582
|
+
warnings.push(...releaseValidation.warnings);
|
|
320
1583
|
}
|
|
321
1584
|
changedFields.push("release");
|
|
322
1585
|
}
|
|
323
|
-
if (options.blockedBy !== undefined) {
|
|
324
|
-
if (
|
|
1586
|
+
if (options.blockedBy !== undefined || clearFrontMatterKeys.has("blocked_by")) {
|
|
1587
|
+
if (clearFrontMatterKeys.has("blocked_by")) {
|
|
325
1588
|
delete document.front_matter.blocked_by;
|
|
326
1589
|
}
|
|
327
1590
|
else {
|
|
@@ -329,8 +1592,8 @@ export async function runUpdate(id, options, global) {
|
|
|
329
1592
|
}
|
|
330
1593
|
changedFields.push("blocked_by");
|
|
331
1594
|
}
|
|
332
|
-
if (options.blockedReason !== undefined) {
|
|
333
|
-
if (
|
|
1595
|
+
if (options.blockedReason !== undefined || clearFrontMatterKeys.has("blocked_reason")) {
|
|
1596
|
+
if (clearFrontMatterKeys.has("blocked_reason")) {
|
|
334
1597
|
delete document.front_matter.blocked_reason;
|
|
335
1598
|
}
|
|
336
1599
|
else {
|
|
@@ -338,8 +1601,8 @@ export async function runUpdate(id, options, global) {
|
|
|
338
1601
|
}
|
|
339
1602
|
changedFields.push("blocked_reason");
|
|
340
1603
|
}
|
|
341
|
-
if (options.unblockNote !== undefined) {
|
|
342
|
-
if (
|
|
1604
|
+
if (options.unblockNote !== undefined || clearFrontMatterKeys.has("unblock_note")) {
|
|
1605
|
+
if (clearFrontMatterKeys.has("unblock_note")) {
|
|
343
1606
|
delete document.front_matter.unblock_note;
|
|
344
1607
|
}
|
|
345
1608
|
else {
|
|
@@ -347,8 +1610,8 @@ export async function runUpdate(id, options, global) {
|
|
|
347
1610
|
}
|
|
348
1611
|
changedFields.push("unblock_note");
|
|
349
1612
|
}
|
|
350
|
-
if (options.reporter !== undefined) {
|
|
351
|
-
if (
|
|
1613
|
+
if (options.reporter !== undefined || clearFrontMatterKeys.has("reporter")) {
|
|
1614
|
+
if (clearFrontMatterKeys.has("reporter")) {
|
|
352
1615
|
delete document.front_matter.reporter;
|
|
353
1616
|
}
|
|
354
1617
|
else {
|
|
@@ -356,8 +1619,8 @@ export async function runUpdate(id, options, global) {
|
|
|
356
1619
|
}
|
|
357
1620
|
changedFields.push("reporter");
|
|
358
1621
|
}
|
|
359
|
-
if (options.severity !== undefined) {
|
|
360
|
-
if (
|
|
1622
|
+
if (options.severity !== undefined || clearFrontMatterKeys.has("severity")) {
|
|
1623
|
+
if (clearFrontMatterKeys.has("severity")) {
|
|
361
1624
|
delete document.front_matter.severity;
|
|
362
1625
|
}
|
|
363
1626
|
else {
|
|
@@ -365,8 +1628,8 @@ export async function runUpdate(id, options, global) {
|
|
|
365
1628
|
}
|
|
366
1629
|
changedFields.push("severity");
|
|
367
1630
|
}
|
|
368
|
-
if (options.environment !== undefined) {
|
|
369
|
-
if (
|
|
1631
|
+
if (options.environment !== undefined || clearFrontMatterKeys.has("environment")) {
|
|
1632
|
+
if (clearFrontMatterKeys.has("environment")) {
|
|
370
1633
|
delete document.front_matter.environment;
|
|
371
1634
|
}
|
|
372
1635
|
else {
|
|
@@ -374,8 +1637,8 @@ export async function runUpdate(id, options, global) {
|
|
|
374
1637
|
}
|
|
375
1638
|
changedFields.push("environment");
|
|
376
1639
|
}
|
|
377
|
-
if (options.reproSteps !== undefined) {
|
|
378
|
-
if (
|
|
1640
|
+
if (options.reproSteps !== undefined || clearFrontMatterKeys.has("repro_steps")) {
|
|
1641
|
+
if (clearFrontMatterKeys.has("repro_steps")) {
|
|
379
1642
|
delete document.front_matter.repro_steps;
|
|
380
1643
|
}
|
|
381
1644
|
else {
|
|
@@ -383,8 +1646,8 @@ export async function runUpdate(id, options, global) {
|
|
|
383
1646
|
}
|
|
384
1647
|
changedFields.push("repro_steps");
|
|
385
1648
|
}
|
|
386
|
-
if (options.resolution !== undefined) {
|
|
387
|
-
if (
|
|
1649
|
+
if (options.resolution !== undefined || clearFrontMatterKeys.has("resolution")) {
|
|
1650
|
+
if (clearFrontMatterKeys.has("resolution")) {
|
|
388
1651
|
delete document.front_matter.resolution;
|
|
389
1652
|
}
|
|
390
1653
|
else {
|
|
@@ -392,8 +1655,8 @@ export async function runUpdate(id, options, global) {
|
|
|
392
1655
|
}
|
|
393
1656
|
changedFields.push("resolution");
|
|
394
1657
|
}
|
|
395
|
-
if (options.expectedResult !== undefined) {
|
|
396
|
-
if (
|
|
1658
|
+
if (options.expectedResult !== undefined || clearFrontMatterKeys.has("expected_result")) {
|
|
1659
|
+
if (clearFrontMatterKeys.has("expected_result")) {
|
|
397
1660
|
delete document.front_matter.expected_result;
|
|
398
1661
|
}
|
|
399
1662
|
else {
|
|
@@ -401,8 +1664,8 @@ export async function runUpdate(id, options, global) {
|
|
|
401
1664
|
}
|
|
402
1665
|
changedFields.push("expected_result");
|
|
403
1666
|
}
|
|
404
|
-
if (options.actualResult !== undefined) {
|
|
405
|
-
if (
|
|
1667
|
+
if (options.actualResult !== undefined || clearFrontMatterKeys.has("actual_result")) {
|
|
1668
|
+
if (clearFrontMatterKeys.has("actual_result")) {
|
|
406
1669
|
delete document.front_matter.actual_result;
|
|
407
1670
|
}
|
|
408
1671
|
else {
|
|
@@ -410,8 +1673,8 @@ export async function runUpdate(id, options, global) {
|
|
|
410
1673
|
}
|
|
411
1674
|
changedFields.push("actual_result");
|
|
412
1675
|
}
|
|
413
|
-
if (options.affectedVersion !== undefined) {
|
|
414
|
-
if (
|
|
1676
|
+
if (options.affectedVersion !== undefined || clearFrontMatterKeys.has("affected_version")) {
|
|
1677
|
+
if (clearFrontMatterKeys.has("affected_version")) {
|
|
415
1678
|
delete document.front_matter.affected_version;
|
|
416
1679
|
}
|
|
417
1680
|
else {
|
|
@@ -419,8 +1682,8 @@ export async function runUpdate(id, options, global) {
|
|
|
419
1682
|
}
|
|
420
1683
|
changedFields.push("affected_version");
|
|
421
1684
|
}
|
|
422
|
-
if (options.fixedVersion !== undefined) {
|
|
423
|
-
if (
|
|
1685
|
+
if (options.fixedVersion !== undefined || clearFrontMatterKeys.has("fixed_version")) {
|
|
1686
|
+
if (clearFrontMatterKeys.has("fixed_version")) {
|
|
424
1687
|
delete document.front_matter.fixed_version;
|
|
425
1688
|
}
|
|
426
1689
|
else {
|
|
@@ -428,8 +1691,8 @@ export async function runUpdate(id, options, global) {
|
|
|
428
1691
|
}
|
|
429
1692
|
changedFields.push("fixed_version");
|
|
430
1693
|
}
|
|
431
|
-
if (options.component !== undefined) {
|
|
432
|
-
if (
|
|
1694
|
+
if (options.component !== undefined || clearFrontMatterKeys.has("component")) {
|
|
1695
|
+
if (clearFrontMatterKeys.has("component")) {
|
|
433
1696
|
delete document.front_matter.component;
|
|
434
1697
|
}
|
|
435
1698
|
else {
|
|
@@ -437,8 +1700,8 @@ export async function runUpdate(id, options, global) {
|
|
|
437
1700
|
}
|
|
438
1701
|
changedFields.push("component");
|
|
439
1702
|
}
|
|
440
|
-
if (options.regression !== undefined) {
|
|
441
|
-
if (
|
|
1703
|
+
if (options.regression !== undefined || clearFrontMatterKeys.has("regression")) {
|
|
1704
|
+
if (clearFrontMatterKeys.has("regression")) {
|
|
442
1705
|
delete document.front_matter.regression;
|
|
443
1706
|
}
|
|
444
1707
|
else {
|
|
@@ -446,8 +1709,8 @@ export async function runUpdate(id, options, global) {
|
|
|
446
1709
|
}
|
|
447
1710
|
changedFields.push("regression");
|
|
448
1711
|
}
|
|
449
|
-
if (options.customerImpact !== undefined) {
|
|
450
|
-
if (
|
|
1712
|
+
if (options.customerImpact !== undefined || clearFrontMatterKeys.has("customer_impact")) {
|
|
1713
|
+
if (clearFrontMatterKeys.has("customer_impact")) {
|
|
451
1714
|
delete document.front_matter.customer_impact;
|
|
452
1715
|
}
|
|
453
1716
|
else {
|
|
@@ -455,13 +1718,59 @@ export async function runUpdate(id, options, global) {
|
|
|
455
1718
|
}
|
|
456
1719
|
changedFields.push("customer_impact");
|
|
457
1720
|
}
|
|
458
|
-
|
|
1721
|
+
if (options.reminder !== undefined || clearFrontMatterKeys.has("reminders")) {
|
|
1722
|
+
if (clearFrontMatterKeys.has("reminders")) {
|
|
1723
|
+
delete document.front_matter.reminders;
|
|
1724
|
+
}
|
|
1725
|
+
else {
|
|
1726
|
+
document.front_matter.reminders = parseReminderEntries(options.reminder, nowValue);
|
|
1727
|
+
}
|
|
1728
|
+
changedFields.push("reminders");
|
|
1729
|
+
}
|
|
1730
|
+
if (options.event !== undefined || clearFrontMatterKeys.has("events")) {
|
|
1731
|
+
if (clearFrontMatterKeys.has("events")) {
|
|
1732
|
+
delete document.front_matter.events;
|
|
1733
|
+
}
|
|
1734
|
+
else {
|
|
1735
|
+
document.front_matter.events = parseEventEntries(options.event, nowValue);
|
|
1736
|
+
}
|
|
1737
|
+
changedFields.push("events");
|
|
1738
|
+
}
|
|
1739
|
+
for (const definition of runtimeFieldRegistry.definitions) {
|
|
1740
|
+
if (!clearFrontMatterKeys.has(definition.front_matter_key)) {
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
if (document.front_matter[definition.front_matter_key] === undefined) {
|
|
1744
|
+
continue;
|
|
1745
|
+
}
|
|
1746
|
+
delete document.front_matter[definition.front_matter_key];
|
|
1747
|
+
changedFields.push(definition.front_matter_key);
|
|
1748
|
+
}
|
|
1749
|
+
const runtimeFieldUpdates = collectRuntimeUpdateFieldValues(options, runtimeFieldRegistry);
|
|
1750
|
+
for (const [fieldKey, fieldValue] of Object.entries(runtimeFieldUpdates)) {
|
|
1751
|
+
if (clearFrontMatterKeys.has(fieldKey)) {
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
if (JSON.stringify(document.front_matter[fieldKey]) === JSON.stringify(fieldValue)) {
|
|
1755
|
+
continue;
|
|
1756
|
+
}
|
|
1757
|
+
document.front_matter[fieldKey] = fieldValue;
|
|
1758
|
+
changedFields.push(fieldKey);
|
|
1759
|
+
}
|
|
1760
|
+
try {
|
|
1761
|
+
applyRegisteredItemFieldDefaultsAndValidation(document.front_matter, getActiveExtensionRegistrations());
|
|
1762
|
+
}
|
|
1763
|
+
catch (error) {
|
|
1764
|
+
throw new PmCliError(error instanceof Error ? error.message : "Invalid extension item field values", EXIT_CODE.USAGE);
|
|
1765
|
+
}
|
|
1766
|
+
return { changedFields, warnings };
|
|
459
1767
|
},
|
|
460
1768
|
});
|
|
461
1769
|
return {
|
|
462
1770
|
item: result.item,
|
|
463
1771
|
changed_fields: result.changedFields,
|
|
464
|
-
warnings: result.warnings,
|
|
1772
|
+
warnings: [...parentReferenceWarnings, ...result.warnings],
|
|
1773
|
+
...(options.allowAuditUpdate === true || options.allowAuditDepUpdate === true ? { audit_update: true } : {}),
|
|
465
1774
|
};
|
|
466
1775
|
}
|
|
467
1776
|
//# sourceMappingURL=update.js.map
|