@unbrained/pm-cli 2026.5.18 → 2026.5.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +953 -472
- package/README.md +4 -11
- package/dist/cli/bootstrap-args.d.ts +18 -1
- package/dist/cli/bootstrap-args.js +143 -3
- package/dist/cli/bootstrap-args.js.map +1 -1
- package/dist/cli/commander-usage.js +147 -10
- package/dist/cli/commander-usage.js.map +1 -1
- package/dist/cli/commands/annotation-command.d.ts +49 -0
- package/dist/cli/commands/annotation-command.js +135 -0
- package/dist/cli/commands/annotation-command.js.map +1 -0
- package/dist/cli/commands/append.js +5 -8
- package/dist/cli/commands/append.js.map +1 -1
- package/dist/cli/commands/calendar.js +3 -6
- package/dist/cli/commands/calendar.js.map +1 -1
- package/dist/cli/commands/claim.js +15 -24
- package/dist/cli/commands/claim.js.map +1 -1
- package/dist/cli/commands/close.js +63 -10
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/comments.d.ts +5 -0
- package/dist/cli/commands/comments.js +27 -117
- package/dist/cli/commands/comments.js.map +1 -1
- package/dist/cli/commands/completion.d.ts +2 -2
- package/dist/cli/commands/completion.js +203 -63
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/config.d.ts +1 -1
- package/dist/cli/commands/config.js +82 -4
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/context.js +4 -10
- package/dist/cli/commands/context.js.map +1 -1
- package/dist/cli/commands/contracts.js +168 -36
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/create.js +53 -313
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/dedupe-audit.js +7 -4
- package/dist/cli/commands/dedupe-audit.js.map +1 -1
- package/dist/cli/commands/delete.d.ts +3 -0
- package/dist/cli/commands/delete.js +11 -9
- package/dist/cli/commands/delete.js.map +1 -1
- package/dist/cli/commands/docs.d.ts +2 -12
- package/dist/cli/commands/docs.js +8 -316
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/event-validation-messages.d.ts +3 -0
- package/dist/cli/commands/event-validation-messages.js +44 -0
- package/dist/cli/commands/event-validation-messages.js.map +1 -0
- package/dist/cli/commands/extension/bundled-catalog.d.ts +14 -0
- package/dist/cli/commands/extension/bundled-catalog.js +268 -0
- package/dist/cli/commands/extension/bundled-catalog.js.map +1 -0
- package/dist/cli/commands/extension/doctor.d.ts +31 -0
- package/dist/cli/commands/extension/doctor.js +345 -0
- package/dist/cli/commands/extension/doctor.js.map +1 -0
- package/dist/cli/commands/extension/install-sources.d.ts +37 -0
- package/dist/cli/commands/extension/install-sources.js +384 -0
- package/dist/cli/commands/extension/install-sources.js.map +1 -0
- package/dist/cli/commands/extension/managed-state.d.ts +48 -0
- package/dist/cli/commands/extension/managed-state.js +172 -0
- package/dist/cli/commands/extension/managed-state.js.map +1 -0
- package/dist/cli/commands/extension/scaffold.d.ts +14 -0
- package/dist/cli/commands/extension/scaffold.js +169 -0
- package/dist/cli/commands/extension/scaffold.js.map +1 -0
- package/dist/cli/commands/extension/shared.d.ts +14 -0
- package/dist/cli/commands/extension/shared.js +106 -0
- package/dist/cli/commands/extension/shared.js.map +1 -0
- package/dist/cli/commands/extension.d.ts +37 -68
- package/dist/cli/commands/extension.js +157 -1319
- package/dist/cli/commands/extension.js.map +1 -1
- package/dist/cli/commands/files.d.ts +1 -12
- package/dist/cli/commands/files.js +14 -318
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/gc.js +17 -4
- package/dist/cli/commands/gc.js.map +1 -1
- package/dist/cli/commands/get.d.ts +3 -2
- package/dist/cli/commands/get.js +52 -9
- package/dist/cli/commands/get.js.map +1 -1
- package/dist/cli/commands/health.d.ts +10 -0
- package/dist/cli/commands/health.js +269 -76
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history-redact.d.ts +8 -0
- package/dist/cli/commands/history-redact.js +35 -113
- package/dist/cli/commands/history-redact.js.map +1 -1
- package/dist/cli/commands/history-repair.d.ts +33 -0
- package/dist/cli/commands/history-repair.js +172 -0
- package/dist/cli/commands/history-repair.js.map +1 -0
- package/dist/cli/commands/history.d.ts +4 -4
- package/dist/cli/commands/history.js +10 -88
- package/dist/cli/commands/history.js.map +1 -1
- package/dist/cli/commands/index.d.ts +3 -1
- package/dist/cli/commands/index.js +5 -3
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +28 -0
- package/dist/cli/commands/init.js +23 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/learnings.js +20 -119
- package/dist/cli/commands/learnings.js.map +1 -1
- package/dist/cli/commands/legacy-none-tokens.d.ts +3 -0
- package/dist/cli/commands/legacy-none-tokens.js +39 -0
- package/dist/cli/commands/legacy-none-tokens.js.map +1 -0
- package/dist/cli/commands/linked-artifacts.d.ts +96 -0
- package/dist/cli/commands/linked-artifacts.js +335 -0
- package/dist/cli/commands/linked-artifacts.js.map +1 -0
- package/dist/cli/commands/linked-test-entry.d.ts +3 -0
- package/dist/cli/commands/linked-test-entry.js +62 -0
- package/dist/cli/commands/linked-test-entry.js.map +1 -0
- package/dist/cli/commands/linked-test-parsers.d.ts +28 -0
- package/dist/cli/commands/linked-test-parsers.js +192 -0
- package/dist/cli/commands/linked-test-parsers.js.map +1 -0
- package/dist/cli/commands/list.js +49 -24
- package/dist/cli/commands/list.js.map +1 -1
- package/dist/cli/commands/normalize.js +4 -3
- package/dist/cli/commands/normalize.js.map +1 -1
- package/dist/cli/commands/notes.js +20 -119
- package/dist/cli/commands/notes.js.map +1 -1
- package/dist/cli/commands/plan.d.ts +3 -0
- package/dist/cli/commands/plan.js +184 -22
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/recurrence-parsers.d.ts +26 -0
- package/dist/cli/commands/recurrence-parsers.js +98 -0
- package/dist/cli/commands/recurrence-parsers.js.map +1 -0
- package/dist/cli/commands/restore.js +24 -56
- package/dist/cli/commands/restore.js.map +1 -1
- package/dist/cli/commands/schema.d.ts +31 -0
- package/dist/cli/commands/schema.js +98 -0
- package/dist/cli/commands/schema.js.map +1 -0
- package/dist/cli/commands/search.js +154 -42
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/templates.d.ts +4 -0
- package/dist/cli/commands/templates.js +89 -17
- package/dist/cli/commands/templates.js.map +1 -1
- package/dist/cli/commands/test/linked-command-detection.d.ts +37 -0
- package/dist/cli/commands/test/linked-command-detection.js +200 -0
- package/dist/cli/commands/test/linked-command-detection.js.map +1 -0
- package/dist/cli/commands/test-all.js +4 -8
- package/dist/cli/commands/test-all.js.map +1 -1
- package/dist/cli/commands/test.d.ts +2 -2
- package/dist/cli/commands/test.js +12 -357
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update-many.js +6 -9
- package/dist/cli/commands/update-many.js.map +1 -1
- package/dist/cli/commands/update.js +167 -401
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/validate.d.ts +3 -1
- package/dist/cli/commands/validate.js +23 -71
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/error-guidance.d.ts +1 -0
- package/dist/cli/error-guidance.js +100 -6
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/extension-command-help.d.ts +0 -1
- package/dist/cli/extension-command-help.js +2 -13
- package/dist/cli/extension-command-help.js.map +1 -1
- package/dist/cli/extension-command-options.d.ts +1 -0
- package/dist/cli/extension-command-options.js +106 -7
- package/dist/cli/extension-command-options.js.map +1 -1
- package/dist/cli/help-content.d.ts +0 -1
- package/dist/cli/help-content.js +13 -9
- package/dist/cli/help-content.js.map +1 -1
- package/dist/cli/help-json-payload.d.ts +1 -0
- package/dist/cli/help-json-payload.js +33 -3
- package/dist/cli/help-json-payload.js.map +1 -1
- package/dist/cli/main.d.ts +11 -0
- package/dist/cli/main.js +109 -55
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/register-list-query.d.ts +5 -2
- package/dist/cli/register-list-query.js +254 -192
- package/dist/cli/register-list-query.js.map +1 -1
- package/dist/cli/register-mutation.d.ts +1 -1
- package/dist/cli/register-mutation.js +247 -64
- package/dist/cli/register-mutation.js.map +1 -1
- package/dist/cli/register-operations.js +17 -12
- package/dist/cli/register-operations.js.map +1 -1
- package/dist/cli/register-setup.js +33 -16
- package/dist/cli/register-setup.js.map +1 -1
- package/dist/cli/registration-helpers.d.ts +0 -2
- package/dist/cli/registration-helpers.js +14 -40
- package/dist/cli/registration-helpers.js.map +1 -1
- package/dist/cli.js +25 -4
- package/dist/cli.js.map +1 -1
- package/dist/core/config/positional-value.d.ts +44 -0
- package/dist/core/config/positional-value.js +109 -0
- package/dist/core/config/positional-value.js.map +1 -0
- package/dist/core/extensions/extension-capability-aliases.d.ts +14 -0
- package/dist/core/extensions/extension-capability-aliases.js +159 -0
- package/dist/core/extensions/extension-capability-aliases.js.map +1 -0
- package/dist/core/extensions/extension-hook-runtime.d.ts +13 -0
- package/dist/core/extensions/extension-hook-runtime.js +414 -0
- package/dist/core/extensions/extension-hook-runtime.js.map +1 -0
- package/dist/core/extensions/extension-policy.d.ts +69 -0
- package/dist/core/extensions/extension-policy.js +481 -0
- package/dist/core/extensions/extension-policy.js.map +1 -0
- package/dist/core/extensions/extension-registries.d.ts +8 -0
- package/dist/core/extensions/extension-registries.js +52 -0
- package/dist/core/extensions/extension-registries.js.map +1 -0
- package/dist/core/extensions/extension-runtime-helpers.d.ts +6 -0
- package/dist/core/extensions/extension-runtime-helpers.js +29 -0
- package/dist/core/extensions/extension-runtime-helpers.js.map +1 -0
- package/dist/core/extensions/extension-types.d.ts +13 -39
- package/dist/core/extensions/extension-types.js +34 -2
- package/dist/core/extensions/extension-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +7 -1
- package/dist/core/extensions/index.js +11 -14
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +4 -22
- package/dist/core/extensions/loader.js +23 -1146
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/fs/path-utils.d.ts +1 -0
- package/dist/core/fs/path-utils.js +12 -0
- package/dist/core/fs/path-utils.js.map +1 -0
- package/dist/core/history/drift-scan.d.ts +22 -0
- package/dist/core/history/drift-scan.js +149 -0
- package/dist/core/history/drift-scan.js.map +1 -0
- package/dist/core/history/history-rewrite.d.ts +43 -0
- package/dist/core/history/history-rewrite.js +48 -0
- package/dist/core/history/history-rewrite.js.map +1 -0
- package/dist/core/history/history.js +5 -4
- package/dist/core/history/history.js.map +1 -1
- package/dist/core/history/replay.d.ts +82 -0
- package/dist/core/history/replay.js +250 -0
- package/dist/core/history/replay.js.map +1 -0
- package/dist/core/item/item-format.js +11 -8
- package/dist/core/item/item-format.js.map +1 -1
- package/dist/core/item/item-record.d.ts +19 -0
- package/dist/core/item/item-record.js +24 -0
- package/dist/core/item/item-record.js.map +1 -0
- package/dist/core/item/item-type-definition.d.ts +52 -0
- package/dist/core/item/item-type-definition.js +123 -0
- package/dist/core/item/item-type-definition.js.map +1 -0
- package/dist/core/item/parse.js +3 -2
- package/dist/core/item/parse.js.map +1 -1
- package/dist/core/item/priority.d.ts +23 -0
- package/dist/core/item/priority.js +55 -0
- package/dist/core/item/priority.js.map +1 -0
- package/dist/core/item/status.d.ts +14 -1
- package/dist/core/item/status.js +22 -2
- package/dist/core/item/status.js.map +1 -1
- package/dist/core/item/toon-decode.d.ts +19 -0
- package/dist/core/item/toon-decode.js +69 -0
- package/dist/core/item/toon-decode.js.map +1 -0
- package/dist/core/item/type-registry.js +13 -84
- package/dist/core/item/type-registry.js.map +1 -1
- package/dist/core/output/mutation-projection.d.ts +31 -0
- package/dist/core/output/mutation-projection.js +103 -0
- package/dist/core/output/mutation-projection.js.map +1 -0
- package/dist/core/output/output.d.ts +2 -0
- package/dist/core/output/output.js +5 -3
- package/dist/core/output/output.js.map +1 -1
- package/dist/core/packages/manifest.js +3 -9
- package/dist/core/packages/manifest.js.map +1 -1
- package/dist/core/schema/item-types-file.d.ts +85 -0
- package/dist/core/schema/item-types-file.js +243 -0
- package/dist/core/schema/item-types-file.js.map +1 -0
- package/dist/core/schema/runtime-schema.d.ts +2 -1
- package/dist/core/schema/runtime-schema.js +17 -45
- package/dist/core/schema/runtime-schema.js.map +1 -1
- package/dist/core/search/semantic-defaults.js +3 -3
- package/dist/core/search/semantic-defaults.js.map +1 -1
- package/dist/core/search/vector-stores.js +46 -9
- package/dist/core/search/vector-stores.js.map +1 -1
- package/dist/core/sentry/helpers.d.ts +1 -1
- package/dist/core/sentry/helpers.js +20 -3
- package/dist/core/sentry/helpers.js.map +1 -1
- package/dist/core/shared/author.d.ts +1 -0
- package/dist/core/shared/author.js +9 -0
- package/dist/core/shared/author.js.map +1 -0
- package/dist/core/shared/command-types.d.ts +1 -0
- package/dist/core/shared/command-types.js +2 -2
- package/dist/core/shared/command-types.js.map +1 -1
- package/dist/core/shared/constants.d.ts +10 -1
- package/dist/core/shared/constants.js +56 -58
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/lazy-module.d.ts +1 -0
- package/dist/core/shared/lazy-module.js +11 -0
- package/dist/core/shared/lazy-module.js.map +1 -0
- package/dist/core/shared/option-alias-visibility.d.ts +44 -0
- package/dist/core/shared/option-alias-visibility.js +76 -0
- package/dist/core/shared/option-alias-visibility.js.map +1 -0
- package/dist/core/shared/primitives.d.ts +23 -0
- package/dist/core/shared/primitives.js +39 -2
- package/dist/core/shared/primitives.js.map +1 -1
- package/dist/core/shared/text-normalization.d.ts +0 -1
- package/dist/core/shared/text-normalization.js +2 -5
- package/dist/core/shared/text-normalization.js.map +1 -1
- package/dist/core/store/front-matter-cache.d.ts +16 -2
- package/dist/core/store/front-matter-cache.js +99 -33
- package/dist/core/store/front-matter-cache.js.map +1 -1
- package/dist/core/store/item-store.d.ts +2 -0
- package/dist/core/store/item-store.js +76 -110
- package/dist/core/store/item-store.js.map +1 -1
- package/dist/core/store/settings-validator.d.ts +106 -0
- package/dist/core/store/settings-validator.js +279 -0
- package/dist/core/store/settings-validator.js.map +1 -0
- package/dist/core/store/settings.js +6 -343
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/runtime.js +5 -3
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/dist/mcp/server.js +138 -39
- package/dist/mcp/server.js.map +1 -1
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +20 -0
- package/dist/sdk/cli-contracts/enum-contracts.js +156 -0
- package/dist/sdk/cli-contracts/enum-contracts.js.map +1 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +14 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js +243 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js.map +1 -0
- package/dist/sdk/cli-contracts/tool-parameter-tables.d.ts +11 -0
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +901 -0
- package/dist/sdk/cli-contracts/tool-parameter-tables.js.map +1 -0
- package/dist/sdk/cli-contracts.d.ts +18 -33
- package/dist/sdk/cli-contracts.js +96 -1238
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/package-import-adapters.d.ts +74 -0
- package/dist/sdk/package-import-adapters.js +186 -0
- package/dist/sdk/package-import-adapters.js.map +1 -0
- package/dist/sdk/package-runtime-options.d.ts +26 -0
- package/dist/sdk/package-runtime-options.js +71 -0
- package/dist/sdk/package-runtime-options.js.map +1 -0
- package/dist/sdk/runtime.d.ts +27 -1
- package/dist/sdk/runtime.js +48 -3
- package/dist/sdk/runtime.js.map +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.js +10 -2
- package/dist/types.js.map +1 -1
- package/docs/AGENT_GUIDE.md +13 -11
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/CLAUDE_CODE_PLUGIN.md +5 -28
- package/docs/CODEX_PLUGIN.md +5 -5
- package/docs/COMMANDS.md +58 -9
- package/docs/CONFIGURATION.md +16 -1
- package/docs/EXTENSIONS.md +4 -63
- package/docs/RELEASING.md +12 -8
- package/docs/SDK.md +11 -2
- package/marketplace.json +7 -3
- package/package.json +18 -14
- package/packages/pm-beads/extensions/beads/index.js +2 -49
- package/packages/pm-beads/extensions/beads/index.ts +2 -54
- package/packages/pm-beads/extensions/beads/runtime-loader.js +86 -0
- package/packages/pm-beads/extensions/beads/runtime-loader.ts +88 -0
- package/packages/pm-beads/extensions/beads/runtime.js +26 -115
- package/packages/pm-beads/extensions/beads/runtime.ts +33 -132
- package/packages/pm-calendar/README.md +3 -1
- package/packages/pm-calendar/extensions/calendar/index.js +66 -2
- package/packages/pm-calendar/extensions/calendar/index.ts +71 -2
- package/packages/pm-calendar/extensions/calendar/runtime.js +1 -0
- package/packages/pm-calendar/extensions/calendar/runtime.ts +1 -0
- package/packages/pm-governance-audit/extensions/governance-audit/runtime.js +14 -41
- package/packages/pm-governance-audit/extensions/governance-audit/runtime.ts +25 -41
- package/packages/pm-guide-shell/extensions/guide-shell/runtime.js +10 -50
- package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +17 -50
- package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.js +8 -40
- package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.ts +10 -40
- package/packages/pm-search-advanced/README.md +8 -0
- package/packages/pm-search-advanced/extensions/search-advanced/index.js +75 -1
- package/packages/pm-search-advanced/extensions/search-advanced/index.ts +74 -0
- package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +58 -33
- package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +60 -33
- package/packages/pm-templates/extensions/templates/runtime.js +11 -202
- package/packages/pm-templates/extensions/templates/runtime.ts +38 -230
- package/packages/pm-todos/extensions/todos/index.js +3 -50
- package/packages/pm-todos/extensions/todos/index.ts +3 -55
- package/packages/pm-todos/extensions/todos/runtime-loader.js +86 -0
- package/packages/pm-todos/extensions/todos/runtime-loader.ts +88 -0
- package/packages/pm-todos/extensions/todos/runtime.js +24 -117
- package/packages/pm-todos/extensions/todos/runtime.ts +32 -129
- package/plugins/pm-claude/README.md +2 -2
- package/plugins/pm-claude/commands/pm-planner.md +1 -15
- package/plugins/pm-claude/scripts/pm-mcp-server.mjs +5 -2
- package/plugins/pm-claude/skills/pm-planner/SKILL.md +3 -21
- package/plugins/pm-codex/scripts/pm-mcp-server.mjs +15 -6
- package/plugins/pm-codex/skills/pm-native/SKILL.md +1 -13
- package/PRD.md +0 -1734
- package/dist/core/output/command-aware.d.ts +0 -1
- package/dist/core/output/command-aware.js +0 -397
- package/dist/core/output/command-aware.js.map +0 -1
|
@@ -1,124 +1,25 @@
|
|
|
1
1
|
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
6
|
-
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
7
|
-
import { PmCliError } from "../../core/shared/errors.js";
|
|
8
|
-
import { nowIso } from "../../core/shared/time.js";
|
|
9
|
-
import { createStdinTokenResolver, parseCsvKv } from "../../core/item/parse.js";
|
|
10
|
-
import { locateItem, mutateItem, readLocatedItem } from "../../core/store/item-store.js";
|
|
11
|
-
import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
|
|
12
|
-
import { readSettings } from "../../core/store/settings.js";
|
|
13
|
-
import { parseLimit } from "../shared-parsers.js";
|
|
14
|
-
function resolveAuthor(candidate, fallback) {
|
|
15
|
-
const resolved = candidate ?? process.env.PM_AUTHOR ?? fallback;
|
|
16
|
-
const trimmed = resolved.trim();
|
|
17
|
-
return trimmed || "unknown";
|
|
18
|
-
}
|
|
19
|
-
function limitLearnings(values, limit) {
|
|
20
|
-
if (limit === undefined)
|
|
21
|
-
return values;
|
|
22
|
-
if (limit === 0)
|
|
23
|
-
return [];
|
|
24
|
-
return values.slice(Math.max(0, values.length - limit));
|
|
25
|
-
}
|
|
26
|
-
function parseLearningTextInput(raw) {
|
|
27
|
-
const trimmed = raw.trim();
|
|
28
|
-
if (!trimmed) {
|
|
29
|
-
return "";
|
|
30
|
-
}
|
|
31
|
-
const looksStructured = /^(?:[-*+]\s*)?text\s*[:=]/im.test(trimmed) || trimmed.startsWith("```");
|
|
32
|
-
if (!looksStructured) {
|
|
33
|
-
return trimmed;
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
const kv = parseCsvKv(trimmed, "--add");
|
|
37
|
-
const keys = Object.keys(kv).map((key) => key.trim().toLowerCase());
|
|
38
|
-
if (keys.some((key) => key !== "text")) {
|
|
39
|
-
return trimmed;
|
|
40
|
-
}
|
|
41
|
-
const text = kv.text?.trim();
|
|
42
|
-
return text || trimmed;
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return trimmed;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="34fecc22-cb1c-5cf6-b68d-8a89f6d07692")}catch(e){}}();
|
|
3
|
+
import { createStdinTokenResolver } from "../../core/item/parse.js";
|
|
4
|
+
import { parseAnnotationTextInput, runAnnotationCommand } from "./annotation-command.js";
|
|
48
5
|
export async function runLearnings(id, options, global) {
|
|
49
6
|
const stdinResolver = createStdinTokenResolver();
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
learnings,
|
|
67
|
-
count: learnings.length,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const author = resolveAuthor(options.author, settings.author_default);
|
|
71
|
-
const addInput = await stdinResolver.resolveValue(options.add, "--add");
|
|
72
|
-
const text = parseLearningTextInput(addInput ?? "");
|
|
73
|
-
if (!text) {
|
|
74
|
-
throw new PmCliError("--add text cannot be empty", EXIT_CODE.USAGE);
|
|
75
|
-
}
|
|
76
|
-
let result;
|
|
77
|
-
try {
|
|
78
|
-
result = await mutateItem({
|
|
79
|
-
pmRoot,
|
|
80
|
-
settings,
|
|
81
|
-
id,
|
|
82
|
-
op: "learning_add",
|
|
83
|
-
author,
|
|
84
|
-
message: options.message,
|
|
85
|
-
force: options.force,
|
|
86
|
-
bypassAssigneeConflict: Boolean(options.allowAuditLearning || options.allowAuditComment),
|
|
87
|
-
mutate(document) {
|
|
88
|
-
const learnings = document.metadata.learnings ?? [];
|
|
89
|
-
learnings.push({
|
|
90
|
-
created_at: nowIso(),
|
|
91
|
-
author,
|
|
92
|
-
text,
|
|
93
|
-
});
|
|
94
|
-
document.metadata.learnings = learnings;
|
|
95
|
-
return { changedFields: ["learnings"] };
|
|
96
|
-
},
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
if (error instanceof PmCliError &&
|
|
101
|
-
error.exitCode === EXIT_CODE.CONFLICT &&
|
|
102
|
-
error.message.includes("is assigned to") &&
|
|
103
|
-
error.message.includes("Use --force to override")) {
|
|
104
|
-
throw new PmCliError(error.message, error.exitCode, {
|
|
105
|
-
code: "ownership_conflict",
|
|
106
|
-
required: "For append-only learning audits on another owner's item, prefer --allow-audit-learning (legacy alias: --allow-audit-comment) before considering --force.",
|
|
107
|
-
examples: ['pm learnings pm-a1b2 --add "audit learning" --author "reviewer" --allow-audit-learning'],
|
|
108
|
-
nextSteps: [
|
|
109
|
-
"Retry with --allow-audit-learning (or legacy --allow-audit-comment) for append-only learning audits that do not mutate item metadata beyond learnings.",
|
|
110
|
-
"Use --force only when an ownership override is explicitly approved.",
|
|
111
|
-
],
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
116
|
-
const learnings = limitLearnings(result.item.learnings, limit);
|
|
117
|
-
return {
|
|
118
|
-
id: result.item.id,
|
|
119
|
-
learnings,
|
|
120
|
-
count: learnings.length,
|
|
121
|
-
};
|
|
7
|
+
const addInput = options.add === undefined ? undefined : await stdinResolver.resolveValue(options.add, "--add");
|
|
8
|
+
return runAnnotationCommand(id, options, global, {
|
|
9
|
+
input: options.add === undefined ? { mode: "list" } : { mode: "add", value: addInput ?? "", emptyFlag: "--add" },
|
|
10
|
+
collectionKey: "learnings",
|
|
11
|
+
op: "learning_add",
|
|
12
|
+
parseText: (raw) => parseAnnotationTextInput(raw),
|
|
13
|
+
allowAuditBypass: Boolean(options.allowAuditLearning || options.allowAuditComment),
|
|
14
|
+
conflictGuidance: {
|
|
15
|
+
required: "For append-only learning audits on another owner's item, prefer --allow-audit-learning (legacy alias: --allow-audit-comment) before considering --force.",
|
|
16
|
+
examples: ['pm learnings pm-a1b2 --add "audit learning" --author "reviewer" --allow-audit-learning'],
|
|
17
|
+
nextSteps: [
|
|
18
|
+
"Retry with --allow-audit-learning (or legacy --allow-audit-comment) for append-only learning audits that do not mutate item metadata beyond learnings.",
|
|
19
|
+
"Use --force only when an ownership override is explicitly approved.",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
});
|
|
122
23
|
}
|
|
123
24
|
//# sourceMappingURL=learnings.js.map
|
|
124
|
-
//# debugId=
|
|
25
|
+
//# debugId=34fecc22-cb1c-5cf6-b68d-8a89f6d07692
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"learnings.js","sources":["cli/commands/learnings.ts"],"sourceRoot":"/","sourcesContent":["import { pathExists } from \"../../core/fs/fs-utils.js\";\nimport { getActiveExtensionRegistrations } from \"../../core/extensions/index.js\";\nimport { resolveItemTypeRegistry } from \"../../core/item/type-registry.js\";\nimport { EXIT_CODE } from \"../../core/shared/constants.js\";\nimport type { GlobalOptions } from \"../../core/shared/command-types.js\";\nimport { PmCliError } from \"../../core/shared/errors.js\";\nimport { nowIso } from \"../../core/shared/time.js\";\nimport { createStdinTokenResolver, parseCsvKv } from \"../../core/item/parse.js\";\nimport { locateItem, mutateItem, readLocatedItem } from \"../../core/store/item-store.js\";\nimport { getSettingsPath, resolvePmRoot } from \"../../core/store/paths.js\";\nimport { readSettings } from \"../../core/store/settings.js\";\nimport { parseLimit } from \"../shared-parsers.js\";\nimport type { LogNote } from \"../../types/index.js\";\n\nexport interface LearningsCommandOptions {\n add?: string;\n limit?: string;\n author?: string;\n message?: string;\n allowAuditLearning?: boolean;\n allowAuditComment?: boolean;\n force?: boolean;\n}\n\nexport interface LearningsResult {\n id: string;\n learnings: LogNote[];\n count: number;\n}\n\nfunction resolveAuthor(candidate: string | undefined, fallback: string): string {\n const resolved = candidate ?? process.env.PM_AUTHOR ?? fallback;\n const trimmed = resolved.trim();\n return trimmed || \"unknown\";\n}\n\nfunction limitLearnings(values: LogNote[], limit: number | undefined): LogNote[] {\n if (limit === undefined) return values;\n if (limit === 0) return [];\n return values.slice(Math.max(0, values.length - limit));\n}\n\nfunction parseLearningTextInput(raw: string): string {\n const trimmed = raw.trim();\n if (!trimmed) {\n return \"\";\n }\n const looksStructured = /^(?:[-*+]\\s*)?text\\s*[:=]/im.test(trimmed) || trimmed.startsWith(\"```\");\n if (!looksStructured) {\n return trimmed;\n }\n try {\n const kv = parseCsvKv(trimmed, \"--add\");\n const keys = Object.keys(kv).map((key) => key.trim().toLowerCase());\n if (keys.some((key) => key !== \"text\")) {\n return trimmed;\n }\n const text = kv.text?.trim();\n return text || trimmed;\n } catch {\n return trimmed;\n }\n}\n\nexport async function runLearnings(\n id: string,\n options: LearningsCommandOptions,\n global: GlobalOptions,\n): Promise<LearningsResult> {\n const stdinResolver = createStdinTokenResolver();\n const pmRoot = resolvePmRoot(process.cwd(), global.path);\n if (!(await pathExists(getSettingsPath(pmRoot)))) {\n throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);\n }\n const settings = await readSettings(pmRoot);\n const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());\n const limit = parseLimit(options.limit);\n\n if (options.add === undefined) {\n const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);\n if (!located) {\n throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);\n }\n const loaded = await readLocatedItem(located, { schema: settings.schema });\n const learnings = limitLearnings(loaded.document.metadata.learnings ?? [], limit);\n return {\n id: located.id,\n learnings,\n count: learnings.length,\n };\n }\n\n const author = resolveAuthor(options.author, settings.author_default);\n const addInput = await stdinResolver.resolveValue(options.add, \"--add\");\n const text = parseLearningTextInput(addInput ?? \"\");\n if (!text) {\n throw new PmCliError(\"--add text cannot be empty\", EXIT_CODE.USAGE);\n }\n\n let result: Awaited<ReturnType<typeof mutateItem>>;\n try {\n result = await mutateItem({\n pmRoot,\n settings,\n id,\n op: \"learning_add\",\n author,\n message: options.message,\n force: options.force,\n bypassAssigneeConflict: Boolean(options.allowAuditLearning || options.allowAuditComment),\n mutate(document) {\n const learnings = document.metadata.learnings ?? [];\n learnings.push({\n created_at: nowIso(),\n author,\n text,\n });\n document.metadata.learnings = learnings;\n return { changedFields: [\"learnings\"] };\n },\n });\n } catch (error: unknown) {\n if (\n error instanceof PmCliError &&\n error.exitCode === EXIT_CODE.CONFLICT &&\n error.message.includes(\"is assigned to\") &&\n error.message.includes(\"Use --force to override\")\n ) {\n throw new PmCliError(error.message, error.exitCode, {\n code: \"ownership_conflict\",\n required:\n \"For append-only learning audits on another owner's item, prefer --allow-audit-learning (legacy alias: --allow-audit-comment) before considering --force.\",\n examples: ['pm learnings pm-a1b2 --add \"audit learning\" --author \"reviewer\" --allow-audit-learning'],\n nextSteps: [\n \"Retry with --allow-audit-learning (or legacy --allow-audit-comment) for append-only learning audits that do not mutate item metadata beyond learnings.\",\n \"Use --force only when an ownership override is explicitly approved.\",\n ],\n });\n }\n throw error;\n }\n\n const learnings = limitLearnings(result.item.learnings as LogNote[], limit);\n return {\n id: result.item.id,\n learnings,\n count: learnings.length,\n };\n}\n"],"names":[],"mappings":"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","debugId":"639c3678-d362-5aaa-ad2e-b3f2138d3ef7"}
|
|
1
|
+
{"version":3,"file":"learnings.js","sources":["cli/commands/learnings.ts"],"sourceRoot":"/","sourcesContent":["import type { GlobalOptions } from \"../../core/shared/command-types.js\";\nimport { createStdinTokenResolver } from \"../../core/item/parse.js\";\nimport type { LogNote } from \"../../types/index.js\";\nimport { parseAnnotationTextInput, runAnnotationCommand } from \"./annotation-command.js\";\n\nexport interface LearningsCommandOptions {\n add?: string;\n limit?: string;\n author?: string;\n message?: string;\n allowAuditLearning?: boolean;\n allowAuditComment?: boolean;\n force?: boolean;\n}\n\nexport interface LearningsResult {\n id: string;\n learnings: LogNote[];\n count: number;\n}\n\nexport async function runLearnings(\n id: string,\n options: LearningsCommandOptions,\n global: GlobalOptions,\n): Promise<LearningsResult> {\n const stdinResolver = createStdinTokenResolver();\n const addInput = options.add === undefined ? undefined : await stdinResolver.resolveValue(options.add, \"--add\");\n\n return runAnnotationCommand<\"learnings\", LogNote>(id, options, global, {\n input: options.add === undefined ? { mode: \"list\" } : { mode: \"add\", value: addInput ?? \"\", emptyFlag: \"--add\" },\n collectionKey: \"learnings\",\n op: \"learning_add\",\n parseText: (raw) => parseAnnotationTextInput(raw),\n allowAuditBypass: Boolean(options.allowAuditLearning || options.allowAuditComment),\n conflictGuidance: {\n required:\n \"For append-only learning audits on another owner's item, prefer --allow-audit-learning (legacy alias: --allow-audit-comment) before considering --force.\",\n examples: ['pm learnings pm-a1b2 --add \"audit learning\" --author \"reviewer\" --allow-audit-learning'],\n nextSteps: [\n \"Retry with --allow-audit-learning (or legacy --allow-audit-comment) for append-only learning audits that do not mutate item metadata beyond learnings.\",\n \"Use --force only when an ownership override is explicitly approved.\",\n ],\n },\n });\n}\n"],"names":[],"mappings":";;AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAkBzF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,EAAU,EACV,OAAgC,EAChC,MAAqB;IAErB,MAAM,aAAa,GAAG,wBAAwB,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAEhH,OAAO,oBAAoB,CAAuB,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;QACrE,KAAK,EAAE,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;QAChH,aAAa,EAAE,WAAW;QAC1B,EAAE,EAAE,cAAc;QAClB,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,wBAAwB,CAAC,GAAG,CAAC;QACjD,gBAAgB,EAAE,OAAO,CAAC,OAAO,CAAC,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,CAAC;QAClF,gBAAgB,EAAE;YAChB,QAAQ,EACN,0JAA0J;YAC5J,QAAQ,EAAE,CAAC,wFAAwF,CAAC;YACpG,SAAS,EAAE;gBACT,wJAAwJ;gBACxJ,qEAAqE;aACtE;SACF;KACF,CAAC,CAAC;AACL,CAAC","debugId":"34fecc22-cb1c-5cf6-b68d-8a89f6d07692"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function isLegacyNoneToken(value: string | undefined): boolean;
|
|
2
|
+
export declare function assertNoLegacyNoneToken(value: string | undefined, flag: string, replacementHint?: string): void;
|
|
3
|
+
export declare function assertNoLegacyNoneTokens(values: string[] | undefined, flag: string, replacementHint?: string): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4e8ab87c-f133-56a8-bf3e-e0f371b72197")}catch(e){}}();
|
|
3
|
+
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
4
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Shared legacy "none"/"null" sentinel handling for the create and update
|
|
7
|
+
* commands. These tokens used to mean "clear this field"; they are now
|
|
8
|
+
* rejected in favour of explicit --unset / --clear-* flags.
|
|
9
|
+
*
|
|
10
|
+
* Extracted verbatim from create.ts and update.ts (pm-why9) — behaviour and
|
|
11
|
+
* error strings are identical to the previous per-command copies.
|
|
12
|
+
*/
|
|
13
|
+
const LEGACY_NONE_TOKENS = new Set(["none", "null"]);
|
|
14
|
+
export function isLegacyNoneToken(value) {
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return LEGACY_NONE_TOKENS.has(value.trim().toLowerCase());
|
|
19
|
+
}
|
|
20
|
+
export function assertNoLegacyNoneToken(value, flag, replacementHint) {
|
|
21
|
+
if (!isLegacyNoneToken(value)) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const suffix = replacementHint ? ` ${replacementHint}` : "";
|
|
25
|
+
throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
|
|
26
|
+
}
|
|
27
|
+
export function assertNoLegacyNoneTokens(values, flag, replacementHint) {
|
|
28
|
+
if (!values || values.length === 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const hasLegacyToken = values.some((value) => isLegacyNoneToken(value));
|
|
32
|
+
if (!hasLegacyToken) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const suffix = replacementHint ? ` ${replacementHint}` : "";
|
|
36
|
+
throw new PmCliError(`${flag} no longer accepts "none" or "null".${suffix}`.trim(), EXIT_CODE.USAGE);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=legacy-none-tokens.js.map
|
|
39
|
+
//# debugId=4e8ab87c-f133-56a8-bf3e-e0f371b72197
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-none-tokens.js","sources":["cli/commands/legacy-none-tokens.ts"],"sourceRoot":"/","sourcesContent":["import { EXIT_CODE } from \"../../core/shared/constants.js\";\nimport { PmCliError } from \"../../core/shared/errors.js\";\n\n/**\n * Shared legacy \"none\"/\"null\" sentinel handling for the create and update\n * commands. These tokens used to mean \"clear this field\"; they are now\n * rejected in favour of explicit --unset / --clear-* flags.\n *\n * Extracted verbatim from create.ts and update.ts (pm-why9) — behaviour and\n * error strings are identical to the previous per-command copies.\n */\nconst LEGACY_NONE_TOKENS = new Set([\"none\", \"null\"]);\n\nexport function isLegacyNoneToken(value: string | undefined): boolean {\n if (value === undefined) {\n return false;\n }\n return LEGACY_NONE_TOKENS.has(value.trim().toLowerCase());\n}\n\nexport function assertNoLegacyNoneToken(value: string | undefined, flag: string, replacementHint?: string): void {\n if (!isLegacyNoneToken(value)) {\n return;\n }\n const suffix = replacementHint ? ` ${replacementHint}` : \"\";\n throw new PmCliError(`${flag} no longer accepts \"none\" or \"null\".${suffix}`.trim(), EXIT_CODE.USAGE);\n}\n\nexport function assertNoLegacyNoneTokens(values: string[] | undefined, flag: string, replacementHint?: string): void {\n if (!values || values.length === 0) {\n return;\n }\n const hasLegacyToken = values.some((value) => isLegacyNoneToken(value));\n if (!hasLegacyToken) {\n return;\n }\n const suffix = replacementHint ? ` ${replacementHint}` : \"\";\n throw new PmCliError(`${flag} no longer accepts \"none\" or \"null\".${suffix}`.trim(), EXIT_CODE.USAGE);\n}\n"],"names":[],"mappings":";;AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEzD;;;;;;;GAOG;AACH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAErD,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAyB,EAAE,IAAY,EAAE,eAAwB;IACvG,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,uCAAuC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;AACvG,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAA4B,EAAE,IAAY,EAAE,eAAwB;IAC3G,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,OAAO;IACT,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,uCAAuC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;AACvG,CAAC","debugId":"4e8ab87c-f133-56a8-bf3e-e0f371b72197"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { GlobalOptions } from "../../core/shared/command-types.js";
|
|
2
|
+
import type { LinkScope } from "../../types/index.js";
|
|
3
|
+
export type LinkedArtifact = {
|
|
4
|
+
path: string;
|
|
5
|
+
scope: LinkScope;
|
|
6
|
+
note?: string;
|
|
7
|
+
};
|
|
8
|
+
export interface LinkedArtifactCommandOptions {
|
|
9
|
+
add?: string[];
|
|
10
|
+
addGlob?: string[];
|
|
11
|
+
remove?: string[];
|
|
12
|
+
migrate?: string[];
|
|
13
|
+
list?: boolean;
|
|
14
|
+
appendStable?: boolean;
|
|
15
|
+
validatePaths?: boolean;
|
|
16
|
+
audit?: boolean;
|
|
17
|
+
author?: string;
|
|
18
|
+
message?: string;
|
|
19
|
+
force?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface PathMigration {
|
|
22
|
+
from: string;
|
|
23
|
+
to: string;
|
|
24
|
+
}
|
|
25
|
+
export interface AddGlobEntry {
|
|
26
|
+
pattern: string;
|
|
27
|
+
scope: LinkScope;
|
|
28
|
+
note?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface LinkedPathValidation {
|
|
31
|
+
checked: number;
|
|
32
|
+
existing_files: string[];
|
|
33
|
+
missing_paths: string[];
|
|
34
|
+
non_file_paths: string[];
|
|
35
|
+
}
|
|
36
|
+
export interface LinkedPathAuditEntry {
|
|
37
|
+
path: string;
|
|
38
|
+
linked_by_count: number;
|
|
39
|
+
linked_item_ids: string[];
|
|
40
|
+
}
|
|
41
|
+
export interface LinkedArtifactResult {
|
|
42
|
+
id: string;
|
|
43
|
+
changed: boolean;
|
|
44
|
+
count: number;
|
|
45
|
+
migrations_applied?: number;
|
|
46
|
+
validation?: LinkedPathValidation;
|
|
47
|
+
audit?: LinkedPathAuditEntry[];
|
|
48
|
+
artifacts: LinkedArtifact[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Configuration that adapts the shared linked-artifact command core to a
|
|
52
|
+
* specific resource kind (files or docs) while preserving every behavioral
|
|
53
|
+
* detail of the original twin implementations.
|
|
54
|
+
*/
|
|
55
|
+
export interface LinkedArtifactKindConfig {
|
|
56
|
+
/** Metadata key under which the artifacts are stored (e.g. "files" | "docs"). */
|
|
57
|
+
metadataKey: "files" | "docs";
|
|
58
|
+
/** Mutation op recorded in history (e.g. "files_add" | "docs_add"). */
|
|
59
|
+
op: "files_add" | "docs_add";
|
|
60
|
+
/** Noun used in the "bare <noun> path" --add usage error (e.g. "file" | "doc"). */
|
|
61
|
+
bareNoun: "file" | "doc";
|
|
62
|
+
/**
|
|
63
|
+
* Whether this kind honors the append-stable option. files supports it;
|
|
64
|
+
* docs always sorts and must never expose append-stable behavior.
|
|
65
|
+
*/
|
|
66
|
+
supportsAppendStable: boolean;
|
|
67
|
+
}
|
|
68
|
+
export declare function ensureScope(raw: string | undefined): LinkScope;
|
|
69
|
+
export declare function looksLikeStructuredPathEntry(raw: string): boolean;
|
|
70
|
+
export declare function parseAddEntries(raw: string[] | undefined, bareNoun: "file" | "doc"): LinkedArtifact[];
|
|
71
|
+
export declare function parseAddGlobEntries(raw: string[] | undefined): AddGlobEntry[];
|
|
72
|
+
export declare function parseRemoveEntries(raw: string[] | undefined): string[];
|
|
73
|
+
export declare function parseMigrateEntries(raw: string[] | undefined): PathMigration[];
|
|
74
|
+
export declare function applyPathMigrations(artifactPath: string, migrations: PathMigration[]): string;
|
|
75
|
+
export declare function normalizeLinkedPath(value: string): string;
|
|
76
|
+
export declare function expandAddGlobEntries(entries: AddGlobEntry[]): Promise<LinkedArtifact[]>;
|
|
77
|
+
export declare function artifactKey(value: Pick<LinkedArtifact, "path" | "scope">): string;
|
|
78
|
+
export declare function sortLinkedArtifacts(artifacts: LinkedArtifact[]): LinkedArtifact[];
|
|
79
|
+
export declare function dedupeLinkedArtifacts(artifacts: LinkedArtifact[]): LinkedArtifact[];
|
|
80
|
+
export declare function validateLinkedPaths(paths: string[]): Promise<LinkedPathValidation>;
|
|
81
|
+
export declare function buildLinkedPathAudit(paths: string[], allItems: Array<{
|
|
82
|
+
id: string;
|
|
83
|
+
artifacts?: LinkedArtifact[];
|
|
84
|
+
}>): LinkedPathAuditEntry[];
|
|
85
|
+
/**
|
|
86
|
+
* Shared linked-artifact list/mutate command core used by runFiles and runDocs.
|
|
87
|
+
* The kind config selects metadata key, op, bare-path noun, and whether
|
|
88
|
+
* append-stable ordering is honored, preserving each twin's exact semantics.
|
|
89
|
+
*/
|
|
90
|
+
export declare function runLinkedArtifacts(id: string, options: LinkedArtifactCommandOptions, global: GlobalOptions, config: LinkedArtifactKindConfig): Promise<LinkedArtifactResult>;
|
|
91
|
+
/**
|
|
92
|
+
* Re-key the generic `artifacts` field to the resource-specific name (files/docs)
|
|
93
|
+
* while preserving the original key order and presence so kind-specific result
|
|
94
|
+
* shapes (and their deterministic JSON key ordering) stay byte-identical.
|
|
95
|
+
*/
|
|
96
|
+
export declare function renameArtifactsResultKey(result: LinkedArtifactResult, key: "files" | "docs"): Record<string, unknown>;
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="352e67e3-0c41-5c04-8d2d-3395c6216303")}catch(e){}}();
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import fg from "fast-glob";
|
|
6
|
+
import { pathExists } from "../../core/fs/fs-utils.js";
|
|
7
|
+
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
8
|
+
import { createStdinTokenResolver, parseCsvKv } from "../../core/item/parse.js";
|
|
9
|
+
import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
|
|
10
|
+
import { EXIT_CODE } from "../../core/shared/constants.js";
|
|
11
|
+
import { PmCliError } from "../../core/shared/errors.js";
|
|
12
|
+
import { listAllFrontMatter, locateItem, mutateItem, readLocatedItem } from "../../core/store/item-store.js";
|
|
13
|
+
import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
|
|
14
|
+
import { readSettings } from "../../core/store/settings.js";
|
|
15
|
+
import { SCOPE_VALUES } from "../../types/index.js";
|
|
16
|
+
import { resolveAuthor } from "../../core/shared/author.js";
|
|
17
|
+
export function ensureScope(raw) {
|
|
18
|
+
const value = (raw ?? "project");
|
|
19
|
+
if (!SCOPE_VALUES.includes(value)) {
|
|
20
|
+
throw new PmCliError(`Invalid scope "${raw}". Valid scopes: ${SCOPE_VALUES.join(", ")} (default: project).`, EXIT_CODE.USAGE);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
export function looksLikeStructuredPathEntry(raw) {
|
|
25
|
+
if (raw.startsWith("```") || raw.includes("\n")) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return /^(?:[-*+]\s+)?(?:path|scope|note)\s*[:=]/i.test(raw);
|
|
29
|
+
}
|
|
30
|
+
export function parseAddEntries(raw, bareNoun) {
|
|
31
|
+
if (!raw)
|
|
32
|
+
return [];
|
|
33
|
+
return raw.map((entry) => {
|
|
34
|
+
const trimmed = entry.trim();
|
|
35
|
+
const kv = looksLikeStructuredPathEntry(trimmed) ? parseCsvKv(entry, "--add") : { path: trimmed };
|
|
36
|
+
if (!kv.path) {
|
|
37
|
+
throw new PmCliError(`--add requires path=<value> or a bare ${bareNoun} path`, EXIT_CODE.USAGE);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
path: kv.path,
|
|
41
|
+
scope: ensureScope(kv.scope),
|
|
42
|
+
note: kv.note?.trim() || undefined,
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export function parseAddGlobEntries(raw) {
|
|
47
|
+
if (!raw)
|
|
48
|
+
return [];
|
|
49
|
+
return raw.map((entry) => {
|
|
50
|
+
const trimmed = entry.trim();
|
|
51
|
+
if (!trimmed) {
|
|
52
|
+
throw new PmCliError("--add-glob requires a glob pattern value", EXIT_CODE.USAGE);
|
|
53
|
+
}
|
|
54
|
+
if (trimmed.includes("=") || /^(?:[-*+]\s+)?(?:pattern|glob|path)\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
|
|
55
|
+
const kv = parseCsvKv(trimmed, "--add-glob");
|
|
56
|
+
const pattern = kv.pattern?.trim() || kv.glob?.trim() || kv.path?.trim();
|
|
57
|
+
if (!pattern) {
|
|
58
|
+
throw new PmCliError("--add-glob key/value form requires pattern=<glob>", EXIT_CODE.USAGE);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
pattern,
|
|
62
|
+
scope: ensureScope(kv.scope),
|
|
63
|
+
note: kv.note?.trim() || undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
pattern: trimmed,
|
|
68
|
+
scope: "project",
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export function parseRemoveEntries(raw) {
|
|
73
|
+
if (!raw)
|
|
74
|
+
return [];
|
|
75
|
+
return raw.map((entry) => {
|
|
76
|
+
const trimmed = entry.trim();
|
|
77
|
+
if (!trimmed) {
|
|
78
|
+
throw new PmCliError("--remove requires a path value", EXIT_CODE.USAGE);
|
|
79
|
+
}
|
|
80
|
+
if (trimmed.includes("=") || /^(?:[-*+]\s+)?path\s*[:=]/i.test(trimmed) || trimmed.startsWith("```")) {
|
|
81
|
+
const kv = parseCsvKv(trimmed, "--remove");
|
|
82
|
+
if (!kv.path) {
|
|
83
|
+
throw new PmCliError("--remove key/value form requires path=<value>", EXIT_CODE.USAGE);
|
|
84
|
+
}
|
|
85
|
+
return kv.path;
|
|
86
|
+
}
|
|
87
|
+
return trimmed;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
export function parseMigrateEntries(raw) {
|
|
91
|
+
if (!raw)
|
|
92
|
+
return [];
|
|
93
|
+
return raw.map((entry) => {
|
|
94
|
+
const kv = parseCsvKv(entry, "--migrate");
|
|
95
|
+
const from = kv.from?.trim();
|
|
96
|
+
const to = kv.to?.trim();
|
|
97
|
+
if (!from || !to) {
|
|
98
|
+
throw new PmCliError("--migrate requires from=<value> and to=<value>", EXIT_CODE.USAGE);
|
|
99
|
+
}
|
|
100
|
+
return { from, to };
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function applyPathMigrations(artifactPath, migrations) {
|
|
104
|
+
let next = artifactPath;
|
|
105
|
+
for (const migration of migrations) {
|
|
106
|
+
if (next.startsWith(migration.from)) {
|
|
107
|
+
next = `${migration.to}${next.slice(migration.from.length)}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return next;
|
|
111
|
+
}
|
|
112
|
+
export function normalizeLinkedPath(value) {
|
|
113
|
+
return value.split(path.sep).join("/");
|
|
114
|
+
}
|
|
115
|
+
export async function expandAddGlobEntries(entries) {
|
|
116
|
+
const expanded = [];
|
|
117
|
+
for (const entry of entries) {
|
|
118
|
+
const absolutePattern = path.isAbsolute(entry.pattern);
|
|
119
|
+
const matches = await fg(entry.pattern, {
|
|
120
|
+
cwd: process.cwd(),
|
|
121
|
+
absolute: absolutePattern,
|
|
122
|
+
onlyFiles: true,
|
|
123
|
+
dot: true,
|
|
124
|
+
unique: true,
|
|
125
|
+
followSymbolicLinks: true,
|
|
126
|
+
});
|
|
127
|
+
const sortedMatches = [...new Set(matches.map((match) => normalizeLinkedPath(path.normalize(match))))].sort((left, right) => left.localeCompare(right));
|
|
128
|
+
for (const matchedPath of sortedMatches) {
|
|
129
|
+
expanded.push({
|
|
130
|
+
path: matchedPath,
|
|
131
|
+
scope: entry.scope,
|
|
132
|
+
note: entry.note,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return expanded;
|
|
137
|
+
}
|
|
138
|
+
export function artifactKey(value) {
|
|
139
|
+
return `${value.path}::${value.scope}`;
|
|
140
|
+
}
|
|
141
|
+
export function sortLinkedArtifacts(artifacts) {
|
|
142
|
+
return [...artifacts].sort((left, right) => {
|
|
143
|
+
const byPath = left.path.localeCompare(right.path);
|
|
144
|
+
if (byPath !== 0)
|
|
145
|
+
return byPath;
|
|
146
|
+
return left.scope.localeCompare(right.scope);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
export function dedupeLinkedArtifacts(artifacts) {
|
|
150
|
+
return [...new Map(artifacts.map((entry) => [artifactKey(entry), entry])).values()].map((entry) => ({
|
|
151
|
+
...entry,
|
|
152
|
+
note: entry.note?.trim() || undefined,
|
|
153
|
+
}));
|
|
154
|
+
}
|
|
155
|
+
export async function validateLinkedPaths(paths) {
|
|
156
|
+
const uniquePaths = [...new Set(paths)].sort((left, right) => left.localeCompare(right));
|
|
157
|
+
const existingFiles = [];
|
|
158
|
+
const missingPaths = [];
|
|
159
|
+
const nonFilePaths = [];
|
|
160
|
+
for (const relativePath of uniquePaths) {
|
|
161
|
+
const resolvedPath = path.isAbsolute(relativePath) ? relativePath : path.resolve(process.cwd(), relativePath);
|
|
162
|
+
try {
|
|
163
|
+
const stats = await fs.stat(resolvedPath);
|
|
164
|
+
if (stats.isFile()) {
|
|
165
|
+
existingFiles.push(relativePath);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
nonFilePaths.push(relativePath);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
173
|
+
missingPaths.push(relativePath);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
nonFilePaths.push(relativePath);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
checked: uniquePaths.length,
|
|
181
|
+
existing_files: existingFiles,
|
|
182
|
+
missing_paths: missingPaths,
|
|
183
|
+
non_file_paths: nonFilePaths,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
export function buildLinkedPathAudit(paths, allItems) {
|
|
187
|
+
const index = new Map();
|
|
188
|
+
for (const item of allItems) {
|
|
189
|
+
for (const linkedArtifact of item.artifacts ?? []) {
|
|
190
|
+
const seen = index.get(linkedArtifact.path) ?? new Set();
|
|
191
|
+
seen.add(item.id);
|
|
192
|
+
index.set(linkedArtifact.path, seen);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return [...new Set(paths)]
|
|
196
|
+
.sort((left, right) => left.localeCompare(right))
|
|
197
|
+
.map((linkedPath) => {
|
|
198
|
+
const linkedIds = [...(index.get(linkedPath) ?? new Set())].sort((left, right) => left.localeCompare(right));
|
|
199
|
+
return {
|
|
200
|
+
path: linkedPath,
|
|
201
|
+
linked_by_count: linkedIds.length,
|
|
202
|
+
linked_item_ids: linkedIds,
|
|
203
|
+
};
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Shared linked-artifact list/mutate command core used by runFiles and runDocs.
|
|
208
|
+
* The kind config selects metadata key, op, bare-path noun, and whether
|
|
209
|
+
* append-stable ordering is honored, preserving each twin's exact semantics.
|
|
210
|
+
*/
|
|
211
|
+
export async function runLinkedArtifacts(id, options, global, config) {
|
|
212
|
+
const { metadataKey } = config;
|
|
213
|
+
const stdinResolver = createStdinTokenResolver();
|
|
214
|
+
const pmRoot = resolvePmRoot(process.cwd(), global.path);
|
|
215
|
+
if (!(await pathExists(getSettingsPath(pmRoot)))) {
|
|
216
|
+
throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
|
|
217
|
+
}
|
|
218
|
+
const settings = await readSettings(pmRoot);
|
|
219
|
+
const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
|
|
220
|
+
const resolvedAdds = await stdinResolver.resolveList(options.add, "--add");
|
|
221
|
+
const resolvedAddGlobs = await stdinResolver.resolveList(options.addGlob, "--add-glob");
|
|
222
|
+
const resolvedRemoves = await stdinResolver.resolveList(options.remove, "--remove");
|
|
223
|
+
const resolvedMigrations = await stdinResolver.resolveList(options.migrate, "--migrate");
|
|
224
|
+
const parsedAdds = parseAddEntries(resolvedAdds, config.bareNoun);
|
|
225
|
+
const addGlobs = parseAddGlobEntries(resolvedAddGlobs);
|
|
226
|
+
const expandedGlobAdds = await expandAddGlobEntries(addGlobs);
|
|
227
|
+
const adds = [...parsedAdds, ...expandedGlobAdds];
|
|
228
|
+
const removes = parseRemoveEntries(resolvedRemoves);
|
|
229
|
+
const migrations = parseMigrateEntries(resolvedMigrations);
|
|
230
|
+
const shouldMutate = adds.length > 0 || removes.length > 0 || migrations.length > 0;
|
|
231
|
+
const collectAuditItems = async () => (await listAllFrontMatter(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)).map((entry) => ({
|
|
232
|
+
id: entry.id,
|
|
233
|
+
artifacts: entry[metadataKey],
|
|
234
|
+
}));
|
|
235
|
+
if (!shouldMutate) {
|
|
236
|
+
const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
|
|
237
|
+
if (!located) {
|
|
238
|
+
throw new PmCliError(`Item ${id} not found`, EXIT_CODE.NOT_FOUND);
|
|
239
|
+
}
|
|
240
|
+
const loaded = await readLocatedItem(located, { schema: settings.schema });
|
|
241
|
+
const artifacts = loaded.document.metadata[metadataKey] ?? [];
|
|
242
|
+
return {
|
|
243
|
+
id: located.id,
|
|
244
|
+
artifacts,
|
|
245
|
+
changed: false,
|
|
246
|
+
count: artifacts.length,
|
|
247
|
+
validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,
|
|
248
|
+
audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), await collectAuditItems()) : undefined,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
const author = resolveAuthor(options.author, settings.author_default);
|
|
252
|
+
const result = await mutateItem({
|
|
253
|
+
pmRoot,
|
|
254
|
+
settings,
|
|
255
|
+
id,
|
|
256
|
+
op: config.op,
|
|
257
|
+
author,
|
|
258
|
+
message: options.message,
|
|
259
|
+
force: options.force,
|
|
260
|
+
mutate(document) {
|
|
261
|
+
const metadata = document.metadata;
|
|
262
|
+
const next = [...(metadata[metadataKey] ?? [])];
|
|
263
|
+
let migrationCount = 0;
|
|
264
|
+
if (migrations.length > 0) {
|
|
265
|
+
for (let index = 0; index < next.length; index += 1) {
|
|
266
|
+
const migratedPath = applyPathMigrations(next[index].path, migrations);
|
|
267
|
+
if (migratedPath !== next[index].path) {
|
|
268
|
+
next[index] = { ...next[index], path: migratedPath };
|
|
269
|
+
migrationCount += 1;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const migratedAdds = adds.map((entry) => {
|
|
274
|
+
const migratedPath = applyPathMigrations(entry.path, migrations);
|
|
275
|
+
if (migratedPath !== entry.path) {
|
|
276
|
+
migrationCount += 1;
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
...entry,
|
|
280
|
+
path: migratedPath,
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
const migratedRemoves = removes.map((entry) => applyPathMigrations(entry, migrations));
|
|
284
|
+
for (const add of migratedAdds) {
|
|
285
|
+
const exists = next.some((entry) => entry.path === add.path && entry.scope === add.scope);
|
|
286
|
+
if (!exists) {
|
|
287
|
+
next.push(add);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (migratedRemoves.length > 0) {
|
|
291
|
+
for (let i = next.length - 1; i >= 0; i -= 1) {
|
|
292
|
+
if (migratedRemoves.includes(next[i].path)) {
|
|
293
|
+
next.splice(i, 1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const deduped = dedupeLinkedArtifacts(next);
|
|
298
|
+
const normalized = config.supportsAppendStable && options.appendStable ? deduped : sortLinkedArtifacts(deduped);
|
|
299
|
+
if (normalized.length > 0) {
|
|
300
|
+
metadata[metadataKey] = normalized;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
delete metadata[metadataKey];
|
|
304
|
+
}
|
|
305
|
+
return { changedFields: [metadataKey], warnings: migrationCount > 0 ? [`path_migrations_applied:${migrationCount}`] : [] };
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
const artifacts = result.item[metadataKey] ?? [];
|
|
309
|
+
const migrationWarning = result.warnings.find((warning) => warning.startsWith("path_migrations_applied:"));
|
|
310
|
+
const migrationCount = migrationWarning ? Number(migrationWarning.slice("path_migrations_applied:".length)) : 0;
|
|
311
|
+
const allItems = options.audit ? await collectAuditItems() : [];
|
|
312
|
+
return {
|
|
313
|
+
id: result.item.id,
|
|
314
|
+
artifacts,
|
|
315
|
+
changed: true,
|
|
316
|
+
count: artifacts.length,
|
|
317
|
+
migrations_applied: migrationCount > 0 ? migrationCount : undefined,
|
|
318
|
+
validation: options.validatePaths ? await validateLinkedPaths(artifacts.map((entry) => entry.path)) : undefined,
|
|
319
|
+
audit: options.audit ? buildLinkedPathAudit(artifacts.map((entry) => entry.path), allItems) : undefined,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Re-key the generic `artifacts` field to the resource-specific name (files/docs)
|
|
324
|
+
* while preserving the original key order and presence so kind-specific result
|
|
325
|
+
* shapes (and their deterministic JSON key ordering) stay byte-identical.
|
|
326
|
+
*/
|
|
327
|
+
export function renameArtifactsResultKey(result, key) {
|
|
328
|
+
const out = {};
|
|
329
|
+
for (const [field, value] of Object.entries(result)) {
|
|
330
|
+
out[field === "artifacts" ? key : field] = value;
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=linked-artifacts.js.map
|
|
335
|
+
//# debugId=352e67e3-0c41-5c04-8d2d-3395c6216303
|