@unbrained/pm-cli 2026.10.28 → 2026.10.30
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/cli/commands/lifecycle/append.d.ts +4 -0
- package/dist/cli/commands/lifecycle/append.js +1 -1
- package/dist/cli/commands/lifecycle/create.d.ts +4 -0
- package/dist/cli/commands/lifecycle/create.js +1 -1
- package/dist/cli/commands/lifecycle/plan.d.ts +3 -0
- package/dist/cli/commands/lifecycle/plan.js +1 -1
- package/dist/cli/commands/lifecycle/update-many.d.ts +4 -0
- package/dist/cli/commands/lifecycle/update-many.js +1 -1
- package/dist/cli/commands/lifecycle/update.d.ts +4 -0
- package/dist/cli/commands/lifecycle/update.js +1 -1
- package/dist/cli/help-content.js +2 -2
- package/dist/cli/register-list-query.js +3 -3
- package/dist/cli-bundle/bundle-manifest.json +1 -1
- package/dist/cli-bundle/chunks/{chunk-XHONSCLJ.js → chunk-34MP7WKK.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-42BHHNTL.js +128 -0
- package/dist/cli-bundle/chunks/{chunk-D6P6IBPN.js → chunk-4BQD5SW2.js} +46 -46
- package/dist/cli-bundle/chunks/{chunk-YYD5MNAV.js → chunk-EHBGHX55.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-DM3PICGU.js → chunk-GRABKNFL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-I5O3XZOA.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-CXUQEZDX.js → chunk-LEIVUGDH.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-MVL27TAH.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-7V37RC2L.js → chunk-OH7WPD42.js} +35 -35
- package/dist/cli-bundle/chunks/chunk-OOD2A7AF.js +20 -0
- package/dist/cli-bundle/chunks/chunk-Q5V7P6NM.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-2J7I54MQ.js → chunk-QLPFYBXN.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-S2U7ECUJ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-E5QBZ4HI.js → chunk-SA5NYLPE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YUBUNECD.js → chunk-UUQX3PFD.js} +57 -57
- package/dist/cli-bundle/chunks/chunk-VHLAVTJN.js +31 -0
- package/dist/cli-bundle/chunks/{chunk-DKLEDWVW.js → chunk-XAOVJG52.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-XPQ4RTSF.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-D3AIQZXF.js → chunk-Y6NC3X3E.js} +2 -2
- package/dist/cli-bundle/chunks/item-transaction-WIOBZW4E.js +2 -0
- package/dist/cli-bundle/chunks/{mutation-admission-GKDKHRTZ.js → mutation-admission-TRGAVS7N.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-MHJJUM6M.js → register-list-query-BH4F6M7Z.js} +6 -6
- package/dist/cli-bundle/chunks/register-mutation-5V2NANIS.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-XSFRMUFX.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-WUZ2ZSMY.js → register-setup-QPWSVHFZ.js} +2 -2
- package/dist/cli-bundle/chunks/{stage-2FYJGGG3.js → stage-RTB6RAAO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-2V6NMNYN.js +26 -0
- package/dist/cli-bundle/focused-chunks/{chunk-ML5JIUM6.js → chunk-3SRX77ES.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-YLVHHWHN.js → chunk-4PW5XWVI.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-Z26ZPQH6.js → chunk-ASHGXMX4.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-JTCGDODH.js → chunk-BCIUAEWX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7SZPZOIC.js → chunk-BPE6JTKL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-LPWZERVD.js → chunk-CKBN2D42.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-FRFNGMAK.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-I642DXOT.js +22 -0
- package/dist/cli-bundle/focused-chunks/chunk-K7DKG5HM.js +91 -0
- package/dist/cli-bundle/focused-chunks/chunk-NMQBXU7N.js +44 -0
- package/dist/cli-bundle/focused-chunks/{chunk-6VDRAJYX.js → chunk-PGM3ENGZ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-DRN4W3YJ.js → chunk-POJPJX64.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-B4ZQJEMT.js → chunk-QFNV4JTA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-QUPGBO2L.js → chunk-QVJCQMZY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-R2TPPPVU.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TUN4M757.js → chunk-RGQEJFXO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ON5WFDCG.js → chunk-RKPUQDWF.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-RYEZSZJ7.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-4GN2ZPT5.js → chunk-S23ZUASN.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-R3EA3SDW.js → chunk-SAT7IAEB.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-I4X6AKOO.js → chunk-VFWCSQAG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-VJVJ2ZX2.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-C2GLO7HU.js → chunk-YQUZL2CK.js} +54 -54
- package/dist/cli-bundle/focused-chunks/{chunk-IQKLJFJE.js → chunk-YU7QOYYV.js} +18 -18
- package/dist/cli-bundle/focused-chunks/{indexed-receipt-blobs-5H6RMRTK.js → indexed-receipt-blobs-VK2363JB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/item-transaction-ZFDKJIP7.js +2 -0
- package/dist/cli-bundle/focused-chunks/{mutation-admission-TM3SVU2O.js → mutation-admission-7VUODEPJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{settlement-hook-LBVWWSCF.js → settlement-hook-OK6A7PG2.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{stage-7ZBRX2Q2.js → stage-S5RP5SZH.js} +2 -2
- package/dist/cli-bundle/main.js +3 -3
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +1 -43
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +61 -61
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +9 -9
- package/dist/core/history/operation-contract.d.ts +2 -2
- package/dist/core/history/operation-contract.js +1 -1
- package/dist/core/item/literal-mutation-input.d.ts +12 -0
- package/dist/core/item/literal-mutation-input.js +2 -0
- package/dist/core/item/parse.d.ts +2 -0
- package/dist/core/item/parse.js +2 -2
- package/dist/core/output/output.js +2 -2
- package/dist/core/store/item-store.js +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/item-transaction.d.ts +33 -2
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/lifecycle/append.js +1 -1
- package/dist/sdk/lifecycle/cli-input.d.ts +4 -0
- package/dist/sdk/lifecycle/cli-input.js +2 -0
- package/dist/sdk/lifecycle/create.js +1 -1
- package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -1
- package/dist/sdk/lifecycle/reopen.js +1 -1
- package/dist/sdk/lifecycle/update-many.js +1 -1
- package/dist/sdk/lifecycle/update.js +2 -2
- package/dist/sdk/output/table-rows.d.ts +9 -1
- package/dist/sdk/output/table-rows.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/history.d.ts +2 -0
- package/dist/sdk/query/history.js +1 -1
- package/dist/sdk/runtime/mutation-value-validation.d.ts +16 -0
- package/dist/sdk/runtime/mutation-value-validation.js +2 -0
- package/dist/sdk/runtime-input.js +1 -1
- package/dist/sdk/runtime-primitives.d.ts +1 -0
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime.d.ts +14 -0
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/structured-mutations.js +1 -1
- package/dist/sdk/workspace-transaction-gc.js +1 -1
- package/dist/sdk/workspace-transaction.d.ts +54 -0
- package/dist/sdk/workspace-transaction.js +2 -2
- package/docs/COMMANDS.md +15 -10
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +24 -2
- package/docs/SDK.md +134 -9
- package/docs/TESTING.md +8 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -1
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +6 -3
- package/marketplace.json +1 -1
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/package.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +1 -1
- package/plugins/pm-codex/plugin.json +1 -1
- package/runtime-dependencies.json +1 -1
- package/dist/cli-bundle/chunks/chunk-4D25HF3V.js +0 -2
- package/dist/cli-bundle/chunks/chunk-AHVN4GHF.js +0 -31
- package/dist/cli-bundle/chunks/chunk-CS7QDSUX.js +0 -128
- package/dist/cli-bundle/chunks/chunk-JESLOJD7.js +0 -2
- package/dist/cli-bundle/chunks/chunk-PQLRKFPZ.js +0 -20
- package/dist/cli-bundle/chunks/chunk-SGFQQXFD.js +0 -2
- package/dist/cli-bundle/chunks/chunk-ZX3XMTZG.js +0 -2
- package/dist/cli-bundle/chunks/register-mutation-SN425O3R.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-EYUIUGPW.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3EHVI673.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-46WLWK73.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-6L4KKRK7.js +0 -26
- package/dist/cli-bundle/focused-chunks/chunk-BZSACRVX.js +0 -91
- package/dist/cli-bundle/focused-chunks/chunk-F6UQJJYB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-L5GX2FGZ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-OASYSUOH.js +0 -22
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/** Native item-event vocabulary. New names require an explicit contract change. */
|
|
6
6
|
export declare const PM_ITEM_HISTORY_OPERATIONS:readonly ["append","cancel","claim","close","comment_add","comment_edit","comment_delete","create","delete","docs_add","docs_remove","files_add","files_remove","files_discover","history_author_acknowledge","history_compact","history_compact_baseline","history_redact","history_repair","history_salvage","import","improvement_observe","learning_add","learning_edit","learning_delete","normalize","note_add","note_edit","note_delete","plan_create_metadata","plan_create_initial_step","plan_add_step","plan_reorder_step","plan_remove_step","plan_link_step","plan_unlink_step","plan_append_decision","plan_append_discovery","plan_append_validation","plan_resume","plan_approve","plan_materialize","plan_update_step","plan_complete_step","plan_block_step","policy_approve","policy_refused","release","reopen","restore","schema_migration","schema_migration_reference","test_run_track","tests_add","tests_remove","tests_update","update","update_audit","update_ownership_bypass","workspace_snapshot_restore","extension_migrations_apply","merge_reconcile"];
|
|
7
7
|
/** Exact singleton identities retained for compatibility with existing workspace streams. */
|
|
8
|
-
export declare const PM_WORKSPACE_HISTORY_OPERATIONS:readonly ["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default"];
|
|
8
|
+
export declare const PM_WORKSPACE_HISTORY_OPERATIONS:readonly ["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default","transaction_abandon"];
|
|
9
9
|
/** Retired writer spellings; readers preserve original bytes and may resolve aliases explicitly. */
|
|
10
10
|
export declare const PM_HISTORY_OPERATION_ALIASES:Readonly<Record<string,string>>;
|
|
11
11
|
/** Parameterized operation families whose operands are governed by their owning SDK contracts. */
|
|
@@ -14,7 +14,7 @@ export declare const PM_HISTORY_OPERATION_PATTERNS:readonly ["^config:(?:set|uns
|
|
|
14
14
|
export declare const PM_HISTORY_OPERATION_CONTRACT:{
|
|
15
15
|
readonly version:1;
|
|
16
16
|
readonly item:readonly ["append","cancel","claim","close","comment_add","comment_edit","comment_delete","create","delete","docs_add","docs_remove","files_add","files_remove","files_discover","history_author_acknowledge","history_compact","history_compact_baseline","history_redact","history_repair","history_salvage","import","improvement_observe","learning_add","learning_edit","learning_delete","normalize","note_add","note_edit","note_delete","plan_create_metadata","plan_create_initial_step","plan_add_step","plan_reorder_step","plan_remove_step","plan_link_step","plan_unlink_step","plan_append_decision","plan_append_discovery","plan_append_validation","plan_resume","plan_approve","plan_materialize","plan_update_step","plan_complete_step","plan_block_step","policy_approve","policy_refused","release","reopen","restore","schema_migration","schema_migration_reference","test_run_track","tests_add","tests_remove","tests_update","update","update_audit","update_ownership_bypass","workspace_snapshot_restore","extension_migrations_apply","merge_reconcile"];
|
|
17
|
-
readonly workspace:readonly ["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default"];
|
|
17
|
+
readonly workspace:readonly ["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default","transaction_abandon"];
|
|
18
18
|
readonly aliases:Readonly<Record<string,string>>;
|
|
19
19
|
readonly patterns:readonly ["^config:(?:set|unset):[a-z][a-z0-9_.:-]*$","^assurance:(?:measurement|invariant|gate):(?:put|remove)$","^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$","^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$"];
|
|
20
20
|
readonly read_policy:"preserve_original_operation";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="7e894d1f-fe1a-53f2-9a29-4e9846a9f986")}catch{}})();const PM_ITEM_HISTORY_OPERATIONS=["append","cancel","claim","close","comment_add","comment_edit","comment_delete","create","delete","docs_add","docs_remove","files_add","files_remove","files_discover","history_author_acknowledge","history_compact","history_compact_baseline","history_redact","history_repair","history_salvage","import","improvement_observe","learning_add","learning_edit","learning_delete","normalize","note_add","note_edit","note_delete","plan_create_metadata","plan_create_initial_step","plan_add_step","plan_reorder_step","plan_remove_step","plan_link_step","plan_unlink_step","plan_append_decision","plan_append_discovery","plan_append_validation","plan_resume","plan_approve","plan_materialize","plan_update_step","plan_complete_step","plan_block_step","policy_approve","policy_refused","release","reopen","restore","schema_migration","schema_migration_reference","test_run_track","tests_add","tests_remove","tests_update","update","update_audit","update_ownership_bypass","workspace_snapshot_restore","extension_migrations_apply","merge_reconcile"],PM_WORKSPACE_HISTORY_OPERATIONS=["history:author-acknowledge","settings:write","init:type_preset","templates:save","profile:apply-types","profile:apply-statuses","profile:apply-fields","profile:apply-config","schema:add-type","schema:remove-type","schema:add-status","schema:remove-status","schema:add-field","schema:remove-field","schema:apply-preset","schema:infer-types","schema:policy-put","schema:policy-remove","schema:policy-mode","assurance:bundle:apply","assurance:gate:verdict","telemetry:install_id","telemetry:first_run_prompt","telemetry:clear","item_format:auto_select_default","transaction_abandon"],PM_HISTORY_OPERATION_ALIASES={"init:type-preset":"init:type_preset"},PM_HISTORY_OPERATION_PATTERNS=["^config:(?:set|unset):[a-z][a-z0-9_.:-]*$","^assurance:(?:measurement|invariant|gate):(?:put|remove)$","^schema_(?:rename_type|rename_status|remap_status|rename_field|remove_type|remove_status|remove_field)(?:_compensate)?$","^extension:[a-z][a-z0-9_-]*:[a-z][a-z0-9_]*$"],PM_HISTORY_OPERATION_CONTRACT={version:1,item:PM_ITEM_HISTORY_OPERATIONS,workspace:PM_WORKSPACE_HISTORY_OPERATIONS,aliases:PM_HISTORY_OPERATION_ALIASES,patterns:PM_HISTORY_OPERATION_PATTERNS,read_policy:"preserve_original_operation",custom_operation_grammar:"extension:<package_name>:<snake_case_operation>",legacy_custom_operation_grammar:"lowercase segments separated by underscore, hyphen, colon, or dot; optional opaque colon-suffixed retry key",excluded_surfaces:["json_patch","on_write_hook","telemetry_span"]},declared=new Set([...PM_ITEM_HISTORY_OPERATIONS,...PM_WORKSPACE_HISTORY_OPERATIONS]),patterns=PM_HISTORY_OPERATION_PATTERNS.map(pattern=>new RegExp(pattern,"u"));function resolveHistoryOperation(operation){return Object.hasOwn(PM_HISTORY_OPERATION_ALIASES,operation)?PM_HISTORY_OPERATION_ALIASES[operation]:operation}function requireHistoryOperation(operation){const canonical=resolveHistoryOperation(operation);if(declared.has(canonical)||patterns.some(pattern=>pattern.test(canonical)))return canonical;throw new TypeError("Undeclared history operation; use a native contract identity or extension:<package_name>:<snake_case_operation>.")}function normalizeHistoryOperationForWrite(operation){const canonical=resolveHistoryOperation(operation),colon=canonical.indexOf(":"),prefix=colon<0?canonical:canonical.slice(0,colon),validSuffix=colon<0||colon<canonical.length-1&&!/[\s\p{C}]/u.test(canonical.slice(colon+1));if(/^[a-z][a-z0-9]*(?:[_.-][a-z0-9]+)*$/u.test(prefix)&&validSuffix)return canonical;throw new TypeError("History operation must use lowercase alphanumeric segments with an optional non-whitespace colon-suffixed retry key.")}export{PM_HISTORY_OPERATION_ALIASES,PM_HISTORY_OPERATION_CONTRACT,PM_HISTORY_OPERATION_PATTERNS,PM_ITEM_HISTORY_OPERATIONS,PM_WORKSPACE_HISTORY_OPERATIONS,normalizeHistoryOperationForWrite,requireHistoryOperation,resolveHistoryOperation};
|
|
2
2
|
//# sourceMappingURL=operation-contract.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Opt a CLI adapter into its explicit stdin and legacy clear-token grammar. */
|
|
2
|
+
export declare function markCliMutationInput<T extends object>(input:T):T;
|
|
3
|
+
/** Identify options decoded by a CLI adapter rather than a typed SDK caller. */
|
|
4
|
+
export declare function isCliMutationInput(input:object):boolean;
|
|
5
|
+
/** Keep SDK option strings and collection entries separate from CLI clear tokens. */
|
|
6
|
+
export declare function preserveLiteralMutationInput<T extends object>(input:T):T;
|
|
7
|
+
/** Identify data whose sentinel spellings must pass through ordinary domain validation. */
|
|
8
|
+
export declare function isLiteralMutationInput(input:object,field?:PropertyKey):boolean;
|
|
9
|
+
/** Mark document-derived fields without changing the interpretation of explicit CLI overrides. */
|
|
10
|
+
export declare function preserveLiteralMutationInputFields<T extends object>(input:T,fields:Iterable<PropertyKey>):T;
|
|
11
|
+
/** Preserve literal-data provenance when an internal adapter clones an option bag. */
|
|
12
|
+
export declare function transferLiteralMutationInput<T extends object>(source:object,target:T):T;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="cef883fa-81be-5092-a07b-7a5ca961fbc7")}catch{}})();const literalInputs=new WeakSet,literalFields=new WeakMap,cliInputs=new WeakSet;function markCliMutationInput(input){return cliInputs.add(input),input}function isCliMutationInput(input){return cliInputs.has(input)}function preserveLiteralMutationInput(input){literalInputs.add(input);for(const[key,value]of Object.entries(input)){if(!Array.isArray(value))continue;const owned=[...value];Reflect.set(input,key,owned),literalInputs.add(owned)}return input}function isLiteralMutationInput(input,field){return literalInputs.has(input)||field!==void 0&&literalFields.get(input)?.has(field)===!0}function preserveLiteralMutationInputFields(input,fields){const selected=new Set(fields);literalFields.set(input,selected);for(const field of selected){const value=Reflect.get(input,field);if(!Array.isArray(value))continue;const owned=[...value];Reflect.set(input,field,owned),literalInputs.add(owned)}return input}function transferLiteralMutationInput(source,target){if(isCliMutationInput(source)&&markCliMutationInput(target),isLiteralMutationInput(source))return preserveLiteralMutationInput(target);const fields=literalFields.get(source);return fields?preserveLiteralMutationInputFields(target,fields):target}export{isCliMutationInput,isLiteralMutationInput,markCliMutationInput,preserveLiteralMutationInput,preserveLiteralMutationInputFields,transferLiteralMutationInput};
|
|
2
|
+
//# sourceMappingURL=literal-mutation-input.js.map
|
|
@@ -61,6 +61,8 @@ resolveValue(value:string | undefined,optionName:string,resolveToken?:boolean):P
|
|
|
61
61
|
/** Value that configures or reports resolve list for this contract. */
|
|
62
62
|
resolveList(values:string[] | undefined,optionName:string,resolveToken?:boolean):Promise<string[] | undefined>;
|
|
63
63
|
}
|
|
64
|
+
/** Default domain operations to literal SDK data; only CLI adapters opt into sentinel decoding. */
|
|
65
|
+
export declare function preserveSdkMutationInput<T extends object>(options:T):T;
|
|
64
66
|
/** Mark transport-decoded options whose dash values are data, not stdin tokens. */
|
|
65
67
|
export declare function preserveMutationStdinTokenLiterals<T extends object>(options:T):T;
|
|
66
68
|
/** Mark selected mutation fields whose dash values are literal transport data. */
|
package/dist/core/item/parse.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b2ae2a38-678e-5f49-9f86-6e1ea4210b34")}catch{}})();import{PmCliError}from"../shared/errors.js";import{EXIT_CODE}from"../shared/constants.js";import{isCliMutationInput,preserveLiteralMutationInput,transferLiteralMutationInput}from"./literal-mutation-input.js";const STDIN_TOKEN="-",CONTINUABLE_VALUE_KEYS=new Set(["actual_result","body","cmd","command","customer_impact","description","environment","expected_result","impact","location","message","note","outcome","repro_steps","resolution","text","title","unblock_note","value","why_now"]);function looksLikeStructuredKeyValueEntry(raw,keys){if(raw.startsWith("```")||raw.includes(`
|
|
2
2
|
`))return!0;const keyPattern=keys.map(key=>key.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("|");return new RegExp(`^(?:[-*+]\\s+)?(?:${keyPattern})\\s*[:=]`,"i").test(raw)}function parseTags(raw){const trimmed=raw.trim();if(trimmed==="")return[];const tags=(coerceJsonTagArray(trimmed)??trimmed.split(",")).map(tag=>tag.trim()).filter(Boolean).map(tag=>tag.toLowerCase());return Array.from(new Set(tags)).sort((a,b)=>a.localeCompare(b))}function collectTagFlagValues(values){if(!Array.isArray(values)||values.length===0)return[];const collected=[];for(const raw of values)if(typeof raw=="string")for(const tag of parseTags(raw))collected.push(tag);return Array.from(new Set(collected)).sort((a,b)=>a.localeCompare(b))}function normalizeBaseTags(baseTags){return Array.isArray(baseTags)?baseTags.filter(tag=>typeof tag=="string").map(tag=>tag.trim().toLowerCase()).filter(Boolean):[]}function splitAcceptanceCriteria(value){return typeof value!="string"?[]:value.split(";").map(criterion=>criterion.trim()).filter(Boolean)}function applyAcceptanceCriteriaMutations(baseCriteria,add,remove){const criteria=baseCriteria.map(criterion=>criterion.trim()).filter(Boolean);for(const raw of add??[]){const criterion=raw.trim();if(criterion.includes(";"))throw new PmCliError('Acceptance criteria added with --add-ac cannot contain ";" because semicolons delimit stored criteria',EXIT_CODE.USAGE,{code:"acceptance_criteria_semicolon_forbidden",required:"Pass one semicolon-free criterion per --add-ac value",why:"A semicolon inside one criterion would be re-read as multiple criteria",nextSteps:["Split the text into repeated --add-ac values, or replace the semicolon with punctuation that is not the storage delimiter"]});criterion.length>0&&!criteria.includes(criterion)&&criteria.push(criterion)}const unmatchedRemovals=[];let remaining=criteria;for(const raw of remove??[]){const criterion=raw.trim();if(criterion.length!==0){if(!remaining.includes(criterion)){unmatchedRemovals.push(criterion);continue}remaining=remaining.filter(entry=>entry!==criterion)}}return{criteria:remaining,unmatchedRemovals}}function mergeAdditiveTags(baseTags,add){const normalizedBase=normalizeBaseTags(baseTags);if(!add||add.length===0)return Array.from(new Set(normalizedBase)).sort((a,b)=>a.localeCompare(b));const merged=new Set(normalizedBase);for(const tag of collectTagFlagValues(add))merged.add(tag);return Array.from(merged).sort((a,b)=>a.localeCompare(b))}function applyTagRemovals(baseTags,remove){const normalizedBase=Array.from(new Set(normalizeBaseTags(baseTags))).sort((a,b)=>a.localeCompare(b));if(!remove||remove.length===0)return normalizedBase;const removeSet=new Set(collectTagFlagValues(remove));return removeSet.size===0?normalizedBase:normalizedBase.filter(tag=>!removeSet.has(tag))}function coerceJsonTagArray(trimmed){if(!trimmed.startsWith("["))return null;let parsed;try{parsed=JSON.parse(trimmed)}catch{return null}return parsed.map(entry=>typeof entry=="string"||typeof entry=="number"||typeof entry=="boolean"?String(entry):"").filter(entry=>entry.length>0)}function normalizeLineEndings(value){return value.replace(/\r\n/g,`
|
|
3
3
|
`)}function stripCodeFenceEnvelope(value){const normalized=normalizeLineEndings(value).trim();if(!normalized.startsWith("```"))return value;const lines=normalized.split(`
|
|
4
4
|
`);return lines.length<2||lines.at(-1)?.trim()!=="```"?value:lines.slice(1,-1).join(`
|
|
5
5
|
`)}function splitCsvSegments(raw){const segments=[];let current="",inQuotes=!1;for(let index=0;index<raw.length;index+=1){const char=raw[index];if(char==="\\"&&raw[index+1]===","){current+=",",index+=1;continue}if(char==="\\"&&raw[index+1]!==void 0){current+=`${char}${raw[index+1]}`,index+=1;continue}if(char==='"'){inQuotes=!inQuotes,current+=char;continue}if(char===","&&!inQuotes){segments.push(current),current="";continue}current+=char}return current.trim()&&segments.push(current),segments}function unquoteValue(value){const trimmed=value.trim();if(trimmed.startsWith('"')&&trimmed.endsWith('"')){try{const parsed=JSON.parse(trimmed);if(typeof parsed=="string")return parsed}catch{}return trimmed.slice(1,-1).replace(/\\"/g,'"')}return value}function findKeyValueDelimiter(segment){const equalsIndex=segment.indexOf("="),colonIndex=segment.indexOf(":"),hasEquals=equalsIndex>=0,hasColon=colonIndex>=0;return hasEquals&&hasColon?Math.min(equalsIndex,colonIndex):hasEquals?equalsIndex:hasColon?colonIndex:-1}function buildOptionSpecificKvGuidance(raw,optionName){if((optionName==="--add"||optionName==="--add-glob")&&(/[./\\]/.test(raw)||/\.[a-z]{1,6}$/i.test(raw.trim())))return"For file/doc paths use: path=<file-path>[,scope=project|global]. The scope field is optional and defaults to project (example: path=src/api.ts or path=README.md,scope=project). ";if(optionName!=="--event")return"";const lowered=raw.toLowerCase(),recurrenceHint=lowered.includes("recur_")||lowered.includes("recurrence")?' Recurrence list values must stay in one field and use "|" delimiters (for example recur_by_weekday=mon|wed or recur_by_month_day=1|15).':"",weekdayAliasHint=lowered.includes("recur_byweekday")?" Use recur_by_weekday (with underscores) for weekday recurrence filters.":"";return`${recurrenceHint}${weekdayAliasHint}`}function buildInvalidKvMessage(raw,optionName){const condensed=raw.replaceAll(/\s+/g," ").trim(),preview=condensed.length>160?`${condensed.slice(0,157)}...`:condensed,optionSpecificGuidance=buildOptionSpecificKvGuidance(raw,optionName);return`Invalid ${optionName} value "${preview}". Expected key=value entries separated by commas. `+optionSpecificGuidance+`Also accepts markdown-style key/value lines (for example "- path: README.md"). Use ${optionName} ${STDIN_TOKEN} to read piped stdin input.`}function parseMarkdownKeyValueLines(raw){const normalized=stripCodeFenceEnvelope(raw).trim();if(normalized.length===0||!normalized.includes(`
|
|
6
6
|
`)&&!normalized.startsWith("-")&&!normalized.startsWith("*")&&!normalized.startsWith("+"))return null;const result={};let activeKey;const lines=normalizeLineEndings(normalized).split(`
|
|
7
7
|
`).map(line=>line.trim()).filter(line=>line.length>0);for(const line of lines){const match=line.match(/^(?:[-*+]\s+)?([a-zA-Z0-9_.-]+)\s*(=|:)\s*(.*)$/);if(match){const key=match[1].trim();result[key]=unquoteValue(match[3].trim()),activeKey=key;continue}if(activeKey&&CONTINUABLE_VALUE_KEYS.has(activeKey.toLowerCase())){result[activeKey]=`${result[activeKey]}
|
|
8
|
-
${line}`;continue}return null}return result}function parseCsvKv(raw,optionName){const trimmed=stripCodeFenceEnvelope(raw).trim();if(!trimmed)throw new PmCliError(`${optionName} cannot be empty`,EXIT_CODE.USAGE);const markdownStyle=parseMarkdownKeyValueLines(trimmed);if(markdownStyle)return markdownStyle;const result={};let activeKey;const segments=splitCsvSegments(trimmed);for(const segment of segments){const delimiterIndex=findKeyValueDelimiter(segment);if(delimiterIndex>=0){const key=segment.slice(0,delimiterIndex).trim();if(!key)throw new PmCliError(buildInvalidKvMessage(raw,optionName),EXIT_CODE.USAGE);const value=unquoteValue(segment.slice(delimiterIndex+1).trim());result[key]=value,activeKey=key;continue}if(activeKey&&CONTINUABLE_VALUE_KEYS.has(activeKey.toLowerCase())){result[activeKey]=`${result[activeKey]},${segment}`;continue}throw new PmCliError(buildInvalidKvMessage(raw,optionName),EXIT_CODE.USAGE)}return result}const WINDOWS_ABSOLUTE_PATH_PATTERN=/^[A-Za-z]:[\\/]/,GENERIC_LEADING_KV_KEY_PATTERN=/^(?:[-*+]\s+)?[A-Za-z_][A-Za-z0-9_.-]*\s*=/;function looksLikeGenericKeyValueEntry(raw){const trimmed=raw.trim();return WINDOWS_ABSOLUTE_PATH_PATTERN.test(trimmed)?!1:GENERIC_LEADING_KV_KEY_PATTERN.test(trimmed)}function assertNoAmbiguousBareCommaEntry(raw,optionName,noun,structured){if(!(structured||!raw.includes(",")))throw new PmCliError(`${optionName} received an ambiguous comma-bearing bare ${noun}. Repeat ${optionName} for multiple values, or quote or escape literal commas in a structured key=<value> entry.`,EXIT_CODE.USAGE,{code:"bare_comma_entry_ambiguous",required:`Use one ${optionName} per bare ${noun}, or quote or escape literal commas in a structured key=<value> entry.`})}function assertNoUnknownCsvKeys(kv,optionName,allowedKeys){const allowed=new Set(allowedKeys.map(key=>key.toLowerCase())),unknownKeys=Object.keys(kv).filter(key=>!allowed.has(key.toLowerCase()));if(unknownKeys.length>0)throw new PmCliError(`${optionName} does not recognize key${unknownKeys.length>1?"s":""} ${unknownKeys.map(key=>`"${key}"`).join(", ")}. Allowed keys: ${allowedKeys.join(", ")}.`,EXIT_CODE.USAGE);for(const key of Object.keys(kv)){const normalizedKey=key.toLowerCase();if(normalizedKey!==key){if(Object.hasOwn(kv,normalizedKey))throw new PmCliError(`${optionName} provides key "${key}" more than once after case normalization.`,EXIT_CODE.USAGE);kv[normalizedKey]=kv[key],delete kv[key]}}}async function readStdinText(optionName){if(process.stdin.isTTY===!0)throw new PmCliError(`${optionName} value "${STDIN_TOKEN}" requires piped stdin input. Pipe content into the command, or end manual stdin with Ctrl+D (Unix/macOS) or Ctrl+Z then Enter (Windows).`,EXIT_CODE.USAGE);return process.stdin.setEncoding("utf8"),await new Promise((resolve,reject)=>{let input="";process.stdin.on("data",chunk=>{input+=chunk}),process.stdin.on("end",()=>{resolve(normalizeLineEndings(input))}),process.stdin.on("error",error=>{reject(error)})})}const ALL_MUTATION_STDIN_FIELDS=Symbol("all-mutation-stdin-fields"),literalStdinTokenFields=new WeakMap;function preserveMutationStdinTokenLiterals(options){return literalStdinTokenFields.set(options,ALL_MUTATION_STDIN_FIELDS),options}function preserveMutationStdinTokenFields(options,fields){const current=literalStdinTokenFields.get(options);return current===ALL_MUTATION_STDIN_FIELDS||literalStdinTokenFields.set(options,new Set([...current??[],...fields])),options}function transferMutationStdinTokenPolicy(source,target){const policy=literalStdinTokenFields.get(source);return policy===void 0||literalStdinTokenFields.set(target,policy===ALL_MUTATION_STDIN_FIELDS?policy:new Set(policy)),target}function overlayMutationStdinTokenPolicy(source,target){const sourcePolicy=literalStdinTokenFields.get(source),targetPolicy=literalStdinTokenFields.get(target);return sourcePolicy===void 0||targetPolicy===ALL_MUTATION_STDIN_FIELDS?target:sourcePolicy===ALL_MUTATION_STDIN_FIELDS?(literalStdinTokenFields.set(target,sourcePolicy),target):(literalStdinTokenFields.set(target,new Set([...targetPolicy??[],...sourcePolicy])),target)}function shouldResolveMutationStdinTokens(options){return literalStdinTokenFields.get(options)!==ALL_MUTATION_STDIN_FIELDS}function shouldResolveMutationStdinTokenField(options,field){const literalFields=literalStdinTokenFields.get(options);return literalFields!==ALL_MUTATION_STDIN_FIELDS&&!literalFields?.has(field)}function assertSingleStdinTokenConsumer(candidates){let stdinConsumerOption;for(const candidate of candidates){if(candidate.resolveToken===!1||candidate.value===void 0)continue;const tokenCount=(Array.isArray(candidate.value)?candidate.value:[candidate.value]).filter(value=>value.trim()===STDIN_TOKEN).length;if(tokenCount>1)throw new PmCliError(`${candidate.optionName} accepts "${STDIN_TOKEN}" stdin token at most once per command invocation`,EXIT_CODE.USAGE);if(tokenCount!==0){if(stdinConsumerOption!==void 0&&stdinConsumerOption!==candidate.optionName)throw new PmCliError(`Only one option may use "${STDIN_TOKEN}" stdin token per command invocation. Already used by ${stdinConsumerOption}.`,EXIT_CODE.USAGE);stdinConsumerOption=candidate.optionName}}}async function resolveMutationStdinTokenFields(options,scalarFields,listFields){const source=options,definitions=[...scalarFields,...listFields];assertSingleStdinTokenConsumer(definitions.map(([field,optionName])=>({value:source[field],optionName,resolveToken:shouldResolveMutationStdinTokenField(options,field)})));const stdinResolver=createStdinTokenResolver(),resolved={...source};for(const[field,optionName]of scalarFields)resolved[field]=await stdinResolver.resolveValue(source[field],optionName,shouldResolveMutationStdinTokenField(options,field));for(const[field,optionName]of listFields)resolved[field]=await stdinResolver.resolveList(source[field],optionName,shouldResolveMutationStdinTokenField(options,field));return preserveMutationStdinTokenLiterals(resolved)}function createStdinTokenResolver(){let stdinValuePromise,stdinConsumerOption;const consumeStdin=async optionName=>{if(stdinConsumerOption&&stdinConsumerOption!==optionName)throw new PmCliError(`Only one option may use "${STDIN_TOKEN}" stdin token per command invocation. Already used by ${stdinConsumerOption}.`,EXIT_CODE.USAGE);return stdinConsumerOption=optionName,stdinValuePromise||(stdinValuePromise=readStdinText(optionName)),await stdinValuePromise};return{resolveValue:async(value,optionName,resolveToken=!0)=>{if(!resolveToken)return value;if(value!==void 0)return value.trim()!==STDIN_TOKEN?value:await consumeStdin(optionName)},resolveList:async(values,optionName,resolveToken=!0)=>{if(!resolveToken)return values;if(!values)return;const tokenIndexes=values.map((entry,index)=>entry.trim()===STDIN_TOKEN?index:-1).filter(index=>index>=0);if(tokenIndexes.length===0)return values;if(tokenIndexes.length>1)throw new PmCliError(`${optionName} accepts "${STDIN_TOKEN}" stdin token at most once per command invocation`,EXIT_CODE.USAGE);const stdinValue=await consumeStdin(optionName),next=[...values];return next[tokenIndexes[0]]=stdinValue,next}}}function parseOptionalNumber(raw,optionName){const value=Number(raw);if(!Number.isFinite(value))throw new PmCliError(`Invalid ${optionName} value "${raw}"`,EXIT_CODE.USAGE);return value}function parseOptionalNonNegativeInteger(raw,optionName){const trimmed=raw.trim(),value=Number(trimmed);if(trimmed===""||!Number.isInteger(value)||value<0)throw new PmCliError(`Invalid ${optionName} value "${raw}". Expected a non-negative integer.`,EXIT_CODE.USAGE);return value}const _testOnly={coerceJsonTagArray,stripCodeFenceEnvelope,parseMarkdownKeyValueLines};export{_testOnly,applyAcceptanceCriteriaMutations,applyTagRemovals,assertNoAmbiguousBareCommaEntry,assertNoUnknownCsvKeys,assertSingleStdinTokenConsumer,collectTagFlagValues,createStdinTokenResolver,looksLikeGenericKeyValueEntry,looksLikeStructuredKeyValueEntry,mergeAdditiveTags,overlayMutationStdinTokenPolicy,parseCsvKv,parseOptionalNonNegativeInteger,parseOptionalNumber,parseTags,preserveMutationStdinTokenFields,preserveMutationStdinTokenLiterals,resolveMutationStdinTokenFields,shouldResolveMutationStdinTokenField,shouldResolveMutationStdinTokens,splitAcceptanceCriteria,transferMutationStdinTokenPolicy};
|
|
8
|
+
${line}`;continue}return null}return result}function parseCsvKv(raw,optionName){const trimmed=stripCodeFenceEnvelope(raw).trim();if(!trimmed)throw new PmCliError(`${optionName} cannot be empty`,EXIT_CODE.USAGE);const markdownStyle=parseMarkdownKeyValueLines(trimmed);if(markdownStyle)return markdownStyle;const result={};let activeKey;const segments=splitCsvSegments(trimmed);for(const segment of segments){const delimiterIndex=findKeyValueDelimiter(segment);if(delimiterIndex>=0){const key=segment.slice(0,delimiterIndex).trim();if(!key)throw new PmCliError(buildInvalidKvMessage(raw,optionName),EXIT_CODE.USAGE);const value=unquoteValue(segment.slice(delimiterIndex+1).trim());result[key]=value,activeKey=key;continue}if(activeKey&&CONTINUABLE_VALUE_KEYS.has(activeKey.toLowerCase())){result[activeKey]=`${result[activeKey]},${segment}`;continue}throw new PmCliError(buildInvalidKvMessage(raw,optionName),EXIT_CODE.USAGE)}return result}const WINDOWS_ABSOLUTE_PATH_PATTERN=/^[A-Za-z]:[\\/]/,GENERIC_LEADING_KV_KEY_PATTERN=/^(?:[-*+]\s+)?[A-Za-z_][A-Za-z0-9_.-]*\s*=/;function looksLikeGenericKeyValueEntry(raw){const trimmed=raw.trim();return WINDOWS_ABSOLUTE_PATH_PATTERN.test(trimmed)?!1:GENERIC_LEADING_KV_KEY_PATTERN.test(trimmed)}function assertNoAmbiguousBareCommaEntry(raw,optionName,noun,structured){if(!(structured||!raw.includes(",")))throw new PmCliError(`${optionName} received an ambiguous comma-bearing bare ${noun}. Repeat ${optionName} for multiple values, or quote or escape literal commas in a structured key=<value> entry.`,EXIT_CODE.USAGE,{code:"bare_comma_entry_ambiguous",required:`Use one ${optionName} per bare ${noun}, or quote or escape literal commas in a structured key=<value> entry.`})}function assertNoUnknownCsvKeys(kv,optionName,allowedKeys){const allowed=new Set(allowedKeys.map(key=>key.toLowerCase())),unknownKeys=Object.keys(kv).filter(key=>!allowed.has(key.toLowerCase()));if(unknownKeys.length>0)throw new PmCliError(`${optionName} does not recognize key${unknownKeys.length>1?"s":""} ${unknownKeys.map(key=>`"${key}"`).join(", ")}. Allowed keys: ${allowedKeys.join(", ")}.`,EXIT_CODE.USAGE);for(const key of Object.keys(kv)){const normalizedKey=key.toLowerCase();if(normalizedKey!==key){if(Object.hasOwn(kv,normalizedKey))throw new PmCliError(`${optionName} provides key "${key}" more than once after case normalization.`,EXIT_CODE.USAGE);kv[normalizedKey]=kv[key],delete kv[key]}}}async function readStdinText(optionName){if(process.stdin.isTTY===!0)throw new PmCliError(`${optionName} value "${STDIN_TOKEN}" requires piped stdin input. Pipe content into the command, or end manual stdin with Ctrl+D (Unix/macOS) or Ctrl+Z then Enter (Windows).`,EXIT_CODE.USAGE);return process.stdin.setEncoding("utf8"),await new Promise((resolve,reject)=>{let input="";process.stdin.on("data",chunk=>{input+=chunk}),process.stdin.on("end",()=>{resolve(normalizeLineEndings(input))}),process.stdin.on("error",error=>{reject(error)})})}const ALL_MUTATION_STDIN_FIELDS=Symbol("all-mutation-stdin-fields"),literalStdinTokenFields=new WeakMap;function preserveSdkMutationInput(options){return isCliMutationInput(options)?options:preserveLiteralMutationInput(preserveMutationStdinTokenLiterals({...options}))}function preserveMutationStdinTokenLiterals(options){return literalStdinTokenFields.set(options,ALL_MUTATION_STDIN_FIELDS),options}function preserveMutationStdinTokenFields(options,fields){const current=literalStdinTokenFields.get(options);return current===ALL_MUTATION_STDIN_FIELDS||literalStdinTokenFields.set(options,new Set([...current??[],...fields])),options}function transferMutationStdinTokenPolicy(source,target){transferLiteralMutationInput(source,target);const policy=literalStdinTokenFields.get(source);return policy===void 0||literalStdinTokenFields.set(target,policy===ALL_MUTATION_STDIN_FIELDS?policy:new Set(policy)),target}function overlayMutationStdinTokenPolicy(source,target){const sourcePolicy=literalStdinTokenFields.get(source),targetPolicy=literalStdinTokenFields.get(target);return sourcePolicy===void 0||targetPolicy===ALL_MUTATION_STDIN_FIELDS?target:sourcePolicy===ALL_MUTATION_STDIN_FIELDS?(literalStdinTokenFields.set(target,sourcePolicy),target):(literalStdinTokenFields.set(target,new Set([...targetPolicy??[],...sourcePolicy])),target)}function shouldResolveMutationStdinTokens(options){return literalStdinTokenFields.get(options)!==ALL_MUTATION_STDIN_FIELDS}function shouldResolveMutationStdinTokenField(options,field){const literalFields=literalStdinTokenFields.get(options);return literalFields!==ALL_MUTATION_STDIN_FIELDS&&!literalFields?.has(field)}function assertSingleStdinTokenConsumer(candidates){let stdinConsumerOption;for(const candidate of candidates){if(candidate.resolveToken===!1||candidate.value===void 0)continue;const tokenCount=(Array.isArray(candidate.value)?candidate.value:[candidate.value]).filter(value=>value.trim()===STDIN_TOKEN).length;if(tokenCount>1)throw new PmCliError(`${candidate.optionName} accepts "${STDIN_TOKEN}" stdin token at most once per command invocation`,EXIT_CODE.USAGE);if(tokenCount!==0){if(stdinConsumerOption!==void 0&&stdinConsumerOption!==candidate.optionName)throw new PmCliError(`Only one option may use "${STDIN_TOKEN}" stdin token per command invocation. Already used by ${stdinConsumerOption}.`,EXIT_CODE.USAGE);stdinConsumerOption=candidate.optionName}}}async function resolveMutationStdinTokenFields(options,scalarFields,listFields){const source=options,definitions=[...scalarFields,...listFields];assertSingleStdinTokenConsumer(definitions.map(([field,optionName])=>({value:source[field],optionName,resolveToken:shouldResolveMutationStdinTokenField(options,field)})));const stdinResolver=createStdinTokenResolver(),resolved={...source};for(const[field,optionName]of scalarFields)resolved[field]=await stdinResolver.resolveValue(source[field],optionName,shouldResolveMutationStdinTokenField(options,field));for(const[field,optionName]of listFields)resolved[field]=await stdinResolver.resolveList(source[field],optionName,shouldResolveMutationStdinTokenField(options,field));return preserveMutationStdinTokenLiterals(transferMutationStdinTokenPolicy(options,resolved))}function createStdinTokenResolver(){let stdinValuePromise,stdinConsumerOption;const consumeStdin=async optionName=>{if(stdinConsumerOption&&stdinConsumerOption!==optionName)throw new PmCliError(`Only one option may use "${STDIN_TOKEN}" stdin token per command invocation. Already used by ${stdinConsumerOption}.`,EXIT_CODE.USAGE);return stdinConsumerOption=optionName,stdinValuePromise||(stdinValuePromise=readStdinText(optionName)),await stdinValuePromise};return{resolveValue:async(value,optionName,resolveToken=!0)=>{if(!resolveToken)return value;if(value!==void 0)return value.trim()!==STDIN_TOKEN?value:await consumeStdin(optionName)},resolveList:async(values,optionName,resolveToken=!0)=>{if(!resolveToken)return values;if(!values)return;const tokenIndexes=values.map((entry,index)=>entry.trim()===STDIN_TOKEN?index:-1).filter(index=>index>=0);if(tokenIndexes.length===0)return values;if(tokenIndexes.length>1)throw new PmCliError(`${optionName} accepts "${STDIN_TOKEN}" stdin token at most once per command invocation`,EXIT_CODE.USAGE);const stdinValue=await consumeStdin(optionName),next=[...values];return next[tokenIndexes[0]]=stdinValue,next}}}function parseOptionalNumber(raw,optionName){const value=Number(raw);if(!Number.isFinite(value))throw new PmCliError(`Invalid ${optionName} value "${raw}"`,EXIT_CODE.USAGE);return value}function parseOptionalNonNegativeInteger(raw,optionName){const trimmed=raw.trim(),value=Number(trimmed);if(trimmed===""||!Number.isInteger(value)||value<0)throw new PmCliError(`Invalid ${optionName} value "${raw}". Expected a non-negative integer.`,EXIT_CODE.USAGE);return value}const _testOnly={coerceJsonTagArray,stripCodeFenceEnvelope,parseMarkdownKeyValueLines};export{_testOnly,applyAcceptanceCriteriaMutations,applyTagRemovals,assertNoAmbiguousBareCommaEntry,assertNoUnknownCsvKeys,assertSingleStdinTokenConsumer,collectTagFlagValues,createStdinTokenResolver,looksLikeGenericKeyValueEntry,looksLikeStructuredKeyValueEntry,mergeAdditiveTags,overlayMutationStdinTokenPolicy,parseCsvKv,parseOptionalNonNegativeInteger,parseOptionalNumber,parseTags,preserveMutationStdinTokenFields,preserveMutationStdinTokenLiterals,preserveSdkMutationInput,resolveMutationStdinTokenFields,shouldResolveMutationStdinTokenField,shouldResolveMutationStdinTokens,splitAcceptanceCriteria,transferMutationStdinTokenPolicy};
|
|
9
9
|
//# sourceMappingURL=parse.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e133d1a6-5e2c-52e7-a98d-1aba50f2d320")}catch{}})();import{getActiveCommandContext,runActiveCommandOverride,runActiveRendererOverride,runActiveServiceOverrideSync,setActiveCommandResult}from"../extensions/index.js";import{EXIT_CODE}from"../shared/constants.js";import{isHostOutputSuppressed}from"./output-control.js";import{projectMutationResult}from"./mutation-projection.js";import{attachReadOutputContracts}from"../../sdk/context-intent-contracts.js";import{attachOutputTokenAccounting}from"../../sdk/output-token-accounting.js";import{propagateContextUsageServingReceipt}from"../../sdk/context-usage.js";import{isReadOutputBudgetExceeded,resolveReadOutputEncoding}from"../../sdk/read-output-contracts.js";import{encode as encodeToon}from"@toon-format/toon";import{encodePmTableRows}from"../../sdk/output/table-rows.js";import{projectPmBriefListEnvelope}from"../../sdk/output/list-envelope.js";const DECLARED_PROCESS_EXIT_CODES=new Set(Object.values(EXIT_CODE)),COLLECTION_COUNT_ALIASES=new Map([["notes_count","notes"],["tests_count","tests"]]),NATIVE_OUTPUT_MARKER="__pm_native_output";let streamErrorHandlersInstalled=!1;function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function setActiveCommandResultOmitted(source){const omitted={read_output:{result_omitted:!0}};propagateContextUsageServingReceipt(source,omitted),setActiveCommandResult(omitted)}function setActiveCommandDeliveryResult(result,receiptSource,structuredDeliveryPreserved){if(structuredDeliveryPreserved){setActiveCommandResult(result);return}setActiveCommandResultOmitted(receiptSource)}function stripNativeOutputMarker(result){if(!isPlainObject(result)||result[NATIVE_OUTPUT_MARKER]!==!0)return result;const{[NATIVE_OUTPUT_MARKER]:_marker,...rest}=result;return rest}function isBrokenPipeError(error){return typeof error=="object"&&error!==null&&error.code==="EPIPE"}function markStdoutBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.SUCCESS)}function markStderrBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.GENERIC_FAILURE)}function markBrokenPipeExitCode(target){if(target==="stdout"){markStdoutBrokenPipeExitCode();return}markStderrBrokenPipeExitCode()}function handleUnhandledStreamError(error){const unhandled=error instanceof Error?error:new Error(String(error));setImmediate(()=>{throw unhandled})}function installStreamErrorHandlers(){streamErrorHandlersInstalled||(streamErrorHandlersInstalled=!0,process.stdout.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stdout");return}handleUnhandledStreamError(error)}),process.stderr.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stderr");return}handleUnhandledStreamError(error)}))}function writeToStream(target,text){installStreamErrorHandlers();try{return target==="stdout"?process.stdout.write(text):process.stderr.write(text),!0}catch(error){if(isBrokenPipeError(error))return markBrokenPipeExitCode(target),!1;throw error}}function writeStdout(text){return writeToStream("stdout",text)}function writeStderr(text){return writeToStream("stderr",text)}function renderScalar(value){return typeof value=="string"?JSON.stringify(value):typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":JSON.stringify(value)}function indentToon(encoded,depth){const indent=" ".repeat(depth);return encoded.split(`
|
|
2
2
|
`).map(line=>`${indent}${line}`).join(`
|
|
3
|
-
`)}function isNestedTableCandidateBounded(rows){const columns=new Set;let presentCells=0;for(const row of rows){const keys=Object.keys(row);presentCells+=keys.length;for(const key of keys)columns.add(key)}return rows.length*columns.size<=presentCells*2}function renderToonObjectEntry(key,entry,depth,allowNestedTable){const indent=" ".repeat(depth);if(!isPlainObject(entry)&&!Array.isArray(entry))return`${indent}${key}: ${renderScalar(entry)}`;if(Array.isArray(entry)){if(entry.length===0)return`${indent}${key}: []`;const expanded=indentToon(encodeToon({[key]:entry}),depth);
|
|
3
|
+
`)}function isNestedTableCandidateBounded(rows){const columns=new Set;let presentCells=0;for(const row of rows){const keys=Object.keys(row);presentCells+=keys.length;for(const key of keys)columns.add(key)}return rows.length*columns.size<=presentCells*2}function renderToonObjectEntry(key,entry,depth,allowNestedTable){const indent=" ".repeat(depth);if(!isPlainObject(entry)&&!Array.isArray(entry))return`${indent}${key}: ${renderScalar(entry)}`;if(Array.isArray(entry)){if(entry.length===0)return`${indent}${key}: []`;const expanded=indentToon(encodeToon({[key]:entry}),depth);return allowNestedTable&&entry.length>=1&&entry.every(isPlainObject)&&isNestedTableCandidateBounded(entry)?[!1,!0].map(compact=>{const table=encodePmTableRows(entry,{compact});return indentToon(encodeToon({[key]:table.rows,[`${key}_encoding`]:table.encoding}),depth)}).reduce((smallest,candidate)=>Buffer.byteLength(candidate)<Buffer.byteLength(smallest)?candidate:smallest,expanded):expanded}return isPlainObject(entry)&&Object.keys(entry).length===0?`${indent}${key}: {}`:`${indent}${key}:
|
|
4
4
|
${renderToonValue(entry,depth+1)}`}function compactToonArray(values,policy,preserveEmpty){const compactedEntries=values.map(entry=>compactToonValue(entry,policy,preserveEmpty||policy.preserveRowFacts&&isPlainObject(entry))).filter(entry=>entry!==void 0);return compactedEntries.length>0||preserveEmpty?compactedEntries:void 0}function compactToonValue(value,policy={omitDuplicateCountAliases:!0,preserveRowFacts:!0},preserveEmpty=!1){if(value===null)return preserveEmpty?null:void 0;if(Array.isArray(value))return compactToonArray(value,policy,preserveEmpty);if(isPlainObject(value)){const compacted=[],entries=Object.entries(value).filter(([key,entry])=>{const canonicalCount=COLLECTION_COUNT_ALIASES.get(key);return!policy.omitDuplicateCountAliases||canonicalCount===void 0||!isPlainObject(value.collection_counts)||entry!==value.collection_counts[canonicalCount]});for(const[key,entry]of entries){if(key==="omitted_field_groups"&&Array.isArray(entry)&&entry.length===0){compacted.push([key,[]]);continue}const compactedEntry=compactToonValue(entry,policy,preserveEmpty);compactedEntry!==void 0&&compacted.push([key,compactedEntry])}return compacted.length>0||preserveEmpty?Object.fromEntries(compacted):void 0}return value}function renderToonValue(value,depth){const indent=" ".repeat(depth);if(Array.isArray(value))return value.length===0?"[]":indentToon(encodeToon(value),depth);if(isPlainObject(value)){const entries=Object.entries(value);return entries.length===0?"{}":entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth,!Object.hasOwn(value,`${key}_encoding`)&&!(key==="checks"&&isPlainObject(value.verdict)&&value.verdict.authority==="ok"))).join(`
|
|
5
5
|
`)}return`${indent}${renderScalar(value)}`}function renderDefaultMarkdownResult(value){if(!isPlainObject(value)||value.output_default!=="markdown"||typeof value.view!="string"||!Array.isArray(value.events)||!Array.isArray(value.days))return null;const lines=[`# pm calendar (${value.view})`,""],summary=isPlainObject(value.summary)?value.summary:{};if(lines.push(`- events: ${String(summary.events??0)}`),lines.push(""),value.events.length===0)return lines.push("No calendar events matched the selected filters."),`${lines.join(`
|
|
6
6
|
`)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="daea02fe-fa67-5891-b31a-517a07faec58")}catch{}})();import fs from"node:fs/promises";import{buildDeletedItemError}from"../history/tombstone.js";import{normalizeHistoryOperationForWrite}from"../history/operation-contract.js";import{enforceWorkflowMutation}from"../policy/workflow-policy-store.js";import{recordItemMetadataEnumeration}from"./item-metadata-read-work.js";import{advanceItemMutationPreconditions,assertItemMutationPreconditions,itemMutationPreconditionHistoryContext}from"./item-mutation-precondition.js";import{checkpointMutationHistoryContext}from"../checkpoint/mutation-context.js";import path from"node:path";import{getActiveExtensionRegistrations,projectAfterCommandItemSnapshot,recordAfterCommandAffectedItem,runActiveOnReadHooks,runActiveBeforeMutationHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{collectRegisteredItemFieldNames}from"../extensions/item-fields.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE,TYPE_TO_FOLDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{levenshteinDistanceWithinLimit}from"../shared/levenshtein.js";import{appendHistoryEntry,createHistoryEntry}from"../history/history.js";import{enforceHistoryStreamPolicyForItem}from"../history/history-stream-policy.js";import{canonicalDocument,parseItemDocument,serializeItemDocument}from"../item/item-format.js";import{resolveItemTypeRegistry}from"../item/type-registry.js";import{effectiveItemFormatVersion,requiredItemFormatVersion}from"../item/item-format-version.js";import{assertProjectRuntimeFormatGuard}from"../../sdk/environment/project-runtime-compatibility.js";import{acquireLockLease}from"../lock/lock.js";import{isFileMissingError,writeFileAtomic}from"../fs/fs-utils.js";import{isUtf8}from"node:buffer";import{normalizeItemId,normalizeRawItemId}from"../item/id.js";import{acquireItemMetadataDerivedIndexLock,listAllDocumentCandidatesCached,listAllDocumentsCached,listAllDocumentsCachedLight,refreshItemMetadataDerivedIndex}from"./item-metadata-cache.js";import{getHistoryPath,getItemPath,ITEM_FILE_EXTENSIONS,resolveWorkspaceRoot}from"./paths.js";import{resolveGovernanceKnobs}from"./settings.js";import{assertReadableTrackerRoot}from"./tracker-preflight.js";import{resolveClaimPrincipal}from"../shared/author.js";import{nowIso}from"../shared/time.js";async function fileExists(targetPath){try{return await fs.access(targetPath),!0}catch{return!1}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}function appendWarning(warnings,warning){warnings&&(warnings.includes(warning)||warnings.push(warning))}function resolveActiveExtensionFieldNames(explicit){return explicit??collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}function resolveItemFormatSearchOrder(preferredFormat){return preferredFormat==="toon"?["toon","json_markdown"]:preferredFormat==="json_markdown"?["json_markdown","toon"]:["toon","json_markdown"]}async function locateItem(pmRoot,rawId,idPrefix="pm-",preferredFormat,typeToFolder=TYPE_TO_FOLDER){const trimmedRawId=rawId.trim(),exactRawId=trimmedRawId.startsWith("#")?trimmedRawId.slice(1):trimmedRawId;if(exactRawId.length===0)return null;const normalizedId=normalizeItemId(rawId,idPrefix),rawNormalizedId=normalizeRawItemId(rawId),candidateIds=[...new Set([exactRawId,normalizedId,rawNormalizedId])].filter(candidateId=>candidateId.length>0),entries=Object.entries(typeToFolder),searchOrder=resolveItemFormatSearchOrder(preferredFormat);for(const candidateId of candidateIds){const matches=new Map;for(const[type]of entries)for(const itemFormat of searchOrder){const itemPath=getItemPath(pmRoot,type,candidateId,itemFormat,typeToFolder);await fileExists(itemPath)&&matches.set(itemPath,matches.get(itemPath)??{id:candidateId,type,itemPath,item_format:itemFormat})}if(matches.size>1){const paths=[...matches.keys()].map(itemPath=>path.relative(pmRoot,itemPath).split(path.sep).join("/")).sort();throw new PmCliError(`Item ${candidateId} has ambiguous identity across ${paths.join(", ")}. Preserve both documents and inspect pm ops validate --check-storage-integrity before resolving the collision.`,EXIT_CODE.CONFLICT,{code:"item_identity_ambiguous",item_id:candidateId,paths})}for(const match of matches.values())return match}return null}async function readLocatedItem(item,options={}){const snapshot=await readLocatedItemSnapshot(item,options);if(snapshot.error!==null)throw snapshot.error;return{raw:snapshot.raw,document:snapshot.document}}async function readLocatedItemSnapshot(item,options={}){const bytes=await fs.readFile(item.itemPath);if(!isUtf8(bytes))throw new PmCliError("Item contains invalid UTF-8; preserve a binary backup before recovering it.",EXIT_CODE.CONFLICT,{code:"item_document_encoding_invalid",item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:!1});const raw=bytes.toString("utf8");await runActiveOnReadHooks({path:item.itemPath,scope:"project"});let document;try{document=parseItemDocument(raw,{format:item.item_format,requireSupportedFormat:!0,schema:options.schema,extensionFieldNames:resolveActiveExtensionFieldNames(options.extensionFieldNames),onWarning:warning=>appendWarning(options.warnings,warning)})}catch(error){if(error instanceof PmCliError&&error.code==="item_format_version_unsupported")throw new PmCliError(`Item ${item.id}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath});if(error instanceof PmCliError&&error.code==="item_document_invalid")return{raw,document:null,error:new PmCliError(`Cannot read ${item.id} at ${item.itemPath}${bytes.length===0?" (zero-length file)":""}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:bytes.length===0,nextSteps:[`Run pm history ${item.id} --full, then pm restore ${item.id} <version> to recover a recorded state.`]})};throw error}return{raw,document,error:null}}async function listAllItemMetadata(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCached(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataLight(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCachedLight(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataWithBody(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema,options={}){await assertReadableTrackerRoot(pmRoot);const candidates=await listAllDocumentCandidatesCached(pmRoot,preferredFormat,typeToFolder,warnings,schema,{includeBody:!0,forceSourceScan:options.forceSourceScan});return recordItemMetadataEnumeration(candidates.length),candidates.map(candidate=>({...candidate.metadata,body:candidate.body}))}function createMutationGuardSdk(params){return{async get(id){const located=await locateItem(params.pmRoot,id,params.settings.id_prefix,params.settings.item_format,params.typeToFolder);if(!located)return null;const{document}=await readLocatedItem(located,{schema:params.settings.schema});return{item:document.metadata,body:document.body}},list:()=>listAllItemMetadata(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema)}}async function listKnownItemIds(pmRoot,typeToFolder){const folders=new Set(Object.values(typeToFolder)),allIds=[];return await Promise.all([...folders].map(async folder=>{try{const entries=await fs.readdir(path.join(pmRoot,folder));for(const entry of entries)for(const ext of ITEM_FILE_EXTENSIONS)if(entry.toLowerCase().endsWith(ext)){allIds.push(entry.slice(0,-ext.length));break}}catch{}})),allIds}async function buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder){const normalized=normalizeItemId(badId,idPrefix),ids=await listKnownItemIds(pmRoot,typeToFolder);if(ids.length===0)return[];const limit=Math.max(3,Math.floor(normalized.length/2));return ids.map(id=>({id,distance:levenshteinDistanceWithinLimit(id,normalized,limit)})).filter(entry=>entry.distance!==null).sort((left,right)=>left.distance-right.distance).slice(0,3).map(entry=>entry.id)}async function buildItemNotFoundError(pmRoot,badId,idPrefix,typeToFolder){const deleted=await buildDeletedItemError(pmRoot,badId,idPrefix);if(deleted)return deleted;const suggestions=await buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder),nextSteps=["Confirm the active --path/PM_PATH scope, then retry with a valid id."];return suggestions.length>0&&nextSteps.unshift(`Did you mean one of: ${suggestions.join(", ")}?`),new PmCliError(`Item ${badId} not found`,EXIT_CODE.NOT_FOUND,{code:"item_not_found",id:badId,nextSteps})}function bypassesAssigneeConflict(op,bypassAssigneeConflict){return op==="claim"||bypassAssigneeConflict===!0&&(op==="comment_add"||op==="comment_edit"||op==="comment_delete"||op==="note_add"||op==="learning_add"||op==="release"||op==="update"||op==="update_ownership_bypass"||op==="update_audit")}async function prepareLockedItem(params){const typeToFolder=params.typeToFolder??resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(params.pmRoot,params.id,params.settings.id_prefix,params.settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(params.pmRoot,params.id,params.settings.id_prefix,typeToFolder);const lease=await acquireLockLease(params.pmRoot,located.id,params.settings.locks.ttl_seconds,params.author,!!params.force,params.settings.governance.force_required_for_stale_lock,params.settings.locks.wait_ms,{waitPolicy:"progress"}),releaseLock=lease.release;try{const warnings=[],{raw:originalRaw,document}=await readLocatedItem(located,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames,warnings}),assigned=document.metadata.assignee?.trim(),assignedPrincipal=document.metadata.claim_principal?.trim()||assigned,callerPrincipal=resolveClaimPrincipal(params.author),governance=resolveGovernanceKnobs(params.settings);if(assigned&&assignedPrincipal!==callerPrincipal&&!params.force&&!bypassesAssigneeConflict(params.op,params.bypassAssigneeConflict)){if(governance.ownership_enforcement==="strict")throw new PmCliError(`Item ${located.id} is assigned to ${assigned}. Use --force to override.`,EXIT_CODE.CONFLICT);governance.ownership_enforcement==="warn"&&warnings.push(`ownership_warning:assignee_conflict:${located.id}:${assigned}`)}return{typeToFolder,located,originalRaw,document,warnings,releaseLock,lease}}catch(error){throw await releaseLock(),error}}async function commitLockedItemWrite(lease,located,originalRaw,commit){return lease.fence(async()=>{let currentRaw;try{currentRaw=await fs.readFile(located.itemPath,"utf8")}catch(error){if(!isFileMissingError(error))throw error;currentRaw=null}if(currentRaw!==originalRaw)throw new PmCliError(`Item ${located.id} changed after this mutation read it; refusing to overwrite the newer revision. Nothing was written.`,EXIT_CODE.CONFLICT,{code:"stale_revision",item_id:located.id,reason:currentRaw===null?"item_removed":"item_revision_changed",required:"Re-read the item and apply the mutation again; the newer stored revision was kept."});return commit()})}function resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter){if(!serviceWriteOverride.handled||typeof serviceWriteOverride.result!="object"||serviceWriteOverride.result===null)return{effectiveTargetItemPath:targetItemPath,effectiveSerializedAfter:serializedAfter,skipItemWrite:!1};const overrideRecord=serviceWriteOverride.result;return{effectiveTargetItemPath:typeof overrideRecord.target_item_path=="string"&&overrideRecord.target_item_path.trim().length>0?overrideRecord.target_item_path:targetItemPath,effectiveSerializedAfter:typeof overrideRecord.contents=="string"?overrideRecord.contents:serializedAfter,skipItemWrite:overrideRecord.skip_write===!0}}async function resolveItemStoreDeleteOverride(payload){const override=await runActiveServiceOverride("item_store_delete",payload),record=override.handled&&typeof override.result=="object"&&override.result!==null?override.result:{};return{effectiveItemPath:typeof record.item_path=="string"&&record.item_path.trim().length>0?record.item_path:payload.item_path,skipDelete:record.skip_delete===!0,warnings:override.warnings}}async function rollbackMutatedItemWrite(params){if(!params.skipItemWrite){if(params.effectiveTargetItemPath!==params.originalItemPath){await writeFileAtomic(params.originalItemPath,params.originalRaw),await fs.rm(params.effectiveTargetItemPath,{force:!0});return}await writeFileAtomic(params.originalItemPath,params.originalRaw)}}async function mutateItemWithDeferredHistoryContext(params){normalizeHistoryOperationForWrite(params.op);const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:params.op,author:params.author,force:params.force,bypassAssigneeConflict:params.bypassAssigneeConflict,extensionFieldNames:params.extensionFieldNames,typeToFolder:params.typeToFolder}),{typeToFolder,located,originalRaw,document,warnings:parseWarnings,releaseLock,lease}=prepared;try{assertItemMutationPreconditions(params.pmRoot,document);const beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutableDocument=canonicalDocument(structuredClone(document),{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutation=await params.mutate(mutableDocument);if(params.skipNoop===!0&&mutation.changedFields.length===0)return{item:beforeDocument.metadata,body:beforeDocument.body,changedFields:[],warnings:[...parseWarnings,...mutation.warnings??[]]};const historyContext={...params.resolveHistoryContext?.(),...checkpointMutationHistoryContext(params.pmRoot,located.id),...itemMutationPreconditionHistoryContext(params.pmRoot,document)},requiredFormat=Math.max(requiredItemFormatVersion(beforeDocument.metadata),requiredItemFormatVersion(mutableDocument.metadata));assertProjectRuntimeFormatGuard(resolveWorkspaceRoot(params.pmRoot),requiredFormat),requiredFormat>effectiveItemFormatVersion(mutableDocument.metadata)&&(mutableDocument.metadata.pm_format_version=requiredFormat,mutation.changedFields.push("pm_format_version")),mutableDocument.metadata.updated_at=nowIso();const afterDocument=canonicalDocument(mutableDocument,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:params.op,author:params.author,before:beforeDocument,after:afterDocument});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:params.op,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields,sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:params.op}),targetItemFormat="toon",serializedAfter=serializeItemDocument(afterDocument,{format:targetItemFormat,schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),targetItemPath=getItemPath(params.pmRoot,afterDocument.metadata.type,located.id,targetItemFormat,typeToFolder),historyPath=getHistoryPath(params.pmRoot,located.id),committed=await commitLockedItemWrite(lease,located,originalRaw,async()=>{const serviceWriteOverride=await runActiveServiceOverride("item_store_write",{op:params.op,pm_root:params.pmRoot,item_id:located.id,source_item_path:located.itemPath,target_item_path:targetItemPath,history_path:historyPath,item_format:targetItemFormat,before:beforeDocument,after:afterDocument,contents:serializedAfter}),{effectiveTargetItemPath:effectiveTargetItemPath2,effectiveSerializedAfter,skipItemWrite}=resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings2=[];try{skipItemWrite||await writeFileAtomic(effectiveTargetItemPath2,effectiveSerializedAfter),!skipItemWrite&&effectiveTargetItemPath2!==located.itemPath&&await fs.rm(located.itemPath);const entry=createHistoryEntry({nowIso:afterDocument.metadata.updated_at,author:params.author,op:params.op,before:beforeDocument,after:afterDocument,message:params.message,context:workflowPolicy.decisions.length===0?Object.keys(historyContext).length===0?void 0:historyContext:{...historyContext,workflow_policies:workflowPolicy.decisions}});try{await appendHistoryEntry(historyPath,entry)}catch(error){throw await rollbackMutatedItemWrite({skipItemWrite,effectiveTargetItemPath:effectiveTargetItemPath2,originalItemPath:located.itemPath,originalRaw}),error}skipItemWrite||(derivedIndexWarnings2=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder,schema:params.settings.schema,itemPath:effectiveTargetItemPath2,previousItemPath:located.itemPath,document:afterDocument}))}finally{await releaseDerivedIndexLock()}return{derivedIndexWarnings:derivedIndexWarnings2,effectiveTargetItemPath:effectiveTargetItemPath2,overrideWarnings:serviceWriteOverride.warnings}}),{derivedIndexWarnings,effectiveTargetItemPath}=committed;advanceItemMutationPreconditions(params.pmRoot,afterDocument);const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveTargetItemPath,scope:"project",op:params.op,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:`${params.op}:history`,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields})];return recordAfterCommandAffectedItem({id:afterDocument.metadata.id,op:params.op,item_type:afterDocument.metadata.type,previous_status:beforeDocument.metadata.status,status:afterDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,mutation.changedFields),current:projectAfterCommandItemSnapshot(afterDocument.metadata,mutation.changedFields),changed_fields:mutation.changedFields}),{item:afterDocument.metadata,body:afterDocument.body,changedFields:mutation.changedFields,warnings:[...parseWarnings,...mutation.warnings??[],...workflowPolicy.warnings,...historyPolicy.warnings,...committed.overrideWarnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}async function mutateItemWithHistoryContext(params){const{historyContext,...mutationParams}=params;return mutateItemWithDeferredHistoryContext({...mutationParams,resolveHistoryContext:()=>historyContext})}async function mutateItemWithHistoryContextResolver(params){return mutateItemWithDeferredHistoryContext(params)}async function mutateItem(params){return mutateItemWithDeferredHistoryContext(params)}const itemStoreTestOnly={appendWarning,bypassesAssigneeConflict,buildDidYouMeanSuggestions,isErrno};async function deleteItem(params){const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:"delete",author:params.author,force:params.force}),{located,originalRaw,document,warnings:parseWarnings,releaseLock,lease}=prepared;try{const extensionFieldNames=resolveActiveExtensionFieldNames(void 0),beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:"delete",author:params.author,before:beforeDocument,after:null,dryRun:params.dryRun});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:"delete",before:beforeDocument,after:null,changed_fields:["deleted"],sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder:prepared.typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:"delete"}),deletionTimestamp=nowIso(),tombstoneDocument=EMPTY_CANONICAL_DOCUMENT,historyEntry=createHistoryEntry({nowIso:deletionTimestamp,author:params.author,op:"delete",before:beforeDocument,after:tombstoneDocument,message:params.message,context:workflowPolicy.decisions.length===0?void 0:{workflow_policies:workflowPolicy.decisions}}),historyPath=getHistoryPath(params.pmRoot,located.id),runDeleteOverride=()=>resolveItemStoreDeleteOverride({op:"delete",pm_root:params.pmRoot,item_id:located.id,item_path:located.itemPath,history_path:historyPath,before:beforeDocument});if(params.dryRun===!0){const preview=await runDeleteOverride();return{item:beforeDocument.metadata,changedFields:["deleted"],targetPath:preview.effectiveItemPath,warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...preview.warnings]}}const committed=await commitLockedItemWrite(lease,located,originalRaw,async()=>{const{effectiveItemPath:effectiveItemPath2,skipDelete,warnings}=await runDeleteOverride(),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings2=[];try{skipDelete||await fs.rm(effectiveItemPath2);try{await appendHistoryEntry(historyPath,historyEntry)}catch(error){throw skipDelete||await writeFileAtomic(effectiveItemPath2,originalRaw),error}skipDelete||(derivedIndexWarnings2=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder:prepared.typeToFolder,schema:params.settings.schema,itemPath:effectiveItemPath2,document:null}))}finally{await releaseDerivedIndexLock()}return{derivedIndexWarnings:derivedIndexWarnings2,effectiveItemPath:effectiveItemPath2,overrideWarnings:warnings}}),{derivedIndexWarnings,effectiveItemPath}=committed,hookWarnings=[...await runActiveOnWriteHooks({path:effectiveItemPath,scope:"project",op:"delete",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:"delete:history",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]})];return recordAfterCommandAffectedItem({id:beforeDocument.metadata.id,op:"delete",item_type:beforeDocument.metadata.type,previous_status:beforeDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,Object.keys(beforeDocument.metadata)),changed_fields:["deleted"]}),{item:beforeDocument.metadata,changedFields:["deleted"],warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...committed.overrideWarnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}export{buildItemNotFoundError,createMutationGuardSdk,deleteItem,itemStoreTestOnly,listAllItemMetadata,listAllItemMetadataLight,listAllItemMetadataWithBody,locateItem,mutateItem,mutateItemWithHistoryContext,mutateItemWithHistoryContextResolver,readLocatedItem,readLocatedItemSnapshot};
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8266acd6-5564-5d56-8025-82608136296d")}catch{}})();import fs from"node:fs/promises";import{buildDeletedItemError}from"../history/tombstone.js";import{normalizeHistoryOperationForWrite}from"../history/operation-contract.js";import{enforceWorkflowMutation}from"../policy/workflow-policy-store.js";import{recordItemMetadataEnumeration}from"./item-metadata-read-work.js";import{advanceItemMutationPreconditions,assertItemMutationPreconditions,itemMutationPreconditionHistoryContext}from"./item-mutation-precondition.js";import{checkpointMutationHistoryContext}from"../checkpoint/mutation-context.js";import path from"node:path";import{getActiveExtensionRegistrations,projectAfterCommandItemSnapshot,recordAfterCommandAffectedItem,runActiveOnReadHooks,runActiveBeforeMutationHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{collectRegisteredItemFieldNames}from"../extensions/item-fields.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE,TYPE_TO_FOLDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{levenshteinDistanceWithinLimit}from"../shared/levenshtein.js";import{appendHistoryEntry,createHistoryEntry}from"../history/history.js";import{enforceHistoryStreamPolicyForItem}from"../history/history-stream-policy.js";import{canonicalDocument,parseItemDocument,serializeItemDocument}from"../item/item-format.js";import{resolveItemTypeRegistry}from"../item/type-registry.js";import{effectiveItemFormatVersion,requiredItemFormatVersion}from"../item/item-format-version.js";import{assertProjectRuntimeFormatGuard}from"../../sdk/environment/project-runtime-compatibility.js";import{acquireLockLease}from"../lock/lock.js";import{isFileMissingError,writeFileAtomic}from"../fs/fs-utils.js";import{isUtf8}from"node:buffer";import{normalizeItemId,normalizeRawItemId}from"../item/id.js";import{acquireItemMetadataDerivedIndexLock,listAllDocumentCandidatesCached,listAllDocumentsCached,listAllDocumentsCachedLight,refreshItemMetadataDerivedIndex}from"./item-metadata-cache.js";import{getHistoryPath,getItemPath,ITEM_FILE_EXTENSIONS,resolveWorkspaceRoot}from"./paths.js";import{resolveGovernanceKnobs}from"./settings.js";import{assertReadableTrackerRoot}from"./tracker-preflight.js";import{resolveClaimPrincipal}from"../shared/author.js";import{nowIso}from"../shared/time.js";async function fileExists(targetPath){try{return await fs.access(targetPath),!0}catch{return!1}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}function appendWarning(warnings,warning){warnings&&(warnings.includes(warning)||warnings.push(warning))}function resolveActiveExtensionFieldNames(explicit){return explicit??collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}function resolveItemFormatSearchOrder(preferredFormat){return preferredFormat==="toon"?["toon","json_markdown"]:preferredFormat==="json_markdown"?["json_markdown","toon"]:["toon","json_markdown"]}async function locateItem(pmRoot,rawId,idPrefix="pm-",preferredFormat,typeToFolder=TYPE_TO_FOLDER){const trimmedRawId=rawId.trim(),exactRawId=trimmedRawId.startsWith("#")?trimmedRawId.slice(1):trimmedRawId;if(exactRawId.length===0)return null;const normalizedId=normalizeItemId(rawId,idPrefix),rawNormalizedId=normalizeRawItemId(rawId),candidateIds=[...new Set([exactRawId,normalizedId,rawNormalizedId])].filter(candidateId=>candidateId.length>0),entries=Object.entries(typeToFolder),searchOrder=resolveItemFormatSearchOrder(preferredFormat);for(const candidateId of candidateIds){const matches=new Map;for(const[type]of entries)for(const itemFormat of searchOrder){const itemPath=getItemPath(pmRoot,type,candidateId,itemFormat,typeToFolder);await fileExists(itemPath)&&matches.set(itemPath,matches.get(itemPath)??{id:candidateId,type,itemPath,item_format:itemFormat})}if(matches.size>1){const paths=[...matches.keys()].map(itemPath=>path.relative(pmRoot,itemPath).split(path.sep).join("/")).sort();throw new PmCliError(`Item ${candidateId} has ambiguous identity across ${paths.join(", ")}. Preserve both documents and inspect pm ops validate --check-storage-integrity before resolving the collision.`,EXIT_CODE.CONFLICT,{code:"item_identity_ambiguous",item_id:candidateId,paths})}for(const match of matches.values())return match}return null}async function readLocatedItem(item,options={}){const snapshot=await readLocatedItemSnapshot(item,options);if(snapshot.error!==null)throw snapshot.error;return{raw:snapshot.raw,document:snapshot.document}}async function readLocatedItemSnapshot(item,options={}){const bytes=await fs.readFile(item.itemPath);if(!isUtf8(bytes))throw new PmCliError("Item contains invalid UTF-8; preserve a binary backup before recovering it.",EXIT_CODE.CONFLICT,{code:"item_document_encoding_invalid",item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:!1});const raw=bytes.toString("utf8");await runActiveOnReadHooks({path:item.itemPath,scope:"project"});let document;try{document=parseItemDocument(raw,{format:item.item_format,requireSupportedFormat:!0,schema:options.schema,extensionFieldNames:resolveActiveExtensionFieldNames(options.extensionFieldNames),onWarning:warning=>appendWarning(options.warnings,warning)})}catch(error){if(error instanceof PmCliError&&error.code==="item_format_version_unsupported")throw new PmCliError(`Item ${item.id}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath});if(error instanceof PmCliError&&error.code==="item_document_invalid")return{raw,document:null,error:new PmCliError(`Cannot read ${item.id} at ${item.itemPath}${bytes.length===0?" (zero-length file)":""}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:bytes.length===0,nextSteps:[`Run pm history ${item.id} --full, then pm restore ${item.id} <version> to recover a recorded state.`]})};throw error}return{raw,document,error:null}}async function listAllItemMetadata(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCached(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataLight(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCachedLight(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataWithBody(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema,options={}){await assertReadableTrackerRoot(pmRoot);const candidates=await listAllDocumentCandidatesCached(pmRoot,preferredFormat,typeToFolder,warnings,schema,{includeBody:!0,forceSourceScan:options.forceSourceScan});return recordItemMetadataEnumeration(candidates.length),candidates.map(candidate=>({...candidate.metadata,body:candidate.body}))}function createMutationGuardSdk(params){return{async get(id){const located=await locateItem(params.pmRoot,id,params.settings.id_prefix,params.settings.item_format,params.typeToFolder);if(!located)return null;const{document}=await readLocatedItem(located,{schema:params.settings.schema});return{item:document.metadata,body:document.body}},list:()=>listAllItemMetadata(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema)}}async function listKnownItemIds(pmRoot,typeToFolder){const folders=new Set(Object.values(typeToFolder)),allIds=[];return await Promise.all([...folders].map(async folder=>{try{const entries=await fs.readdir(path.join(pmRoot,folder));for(const entry of entries)for(const ext of ITEM_FILE_EXTENSIONS)if(entry.toLowerCase().endsWith(ext)){allIds.push(entry.slice(0,-ext.length));break}}catch{}})),allIds}async function buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder){const normalized=normalizeItemId(badId,idPrefix),ids=await listKnownItemIds(pmRoot,typeToFolder);if(ids.length===0)return[];const limit=Math.max(3,Math.floor(normalized.length/2));return ids.map(id=>({id,distance:levenshteinDistanceWithinLimit(id,normalized,limit)})).filter(entry=>entry.distance!==null).sort((left,right)=>left.distance-right.distance).slice(0,3).map(entry=>entry.id)}async function buildItemNotFoundError(pmRoot,badId,idPrefix,typeToFolder){const deleted=await buildDeletedItemError(pmRoot,badId,idPrefix);if(deleted)return deleted;const suggestions=await buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder),nextSteps=["Confirm the active --path/PM_PATH scope, then retry with a valid id."];return suggestions.length>0&&nextSteps.unshift(`Did you mean one of: ${suggestions.join(", ")}?`),new PmCliError(`Item ${badId} not found`,EXIT_CODE.NOT_FOUND,{code:"item_not_found",id:badId,nextSteps})}function bypassesAssigneeConflict(op,bypassAssigneeConflict){return op==="claim"||bypassAssigneeConflict===!0&&(op==="comment_add"||op==="comment_edit"||op==="comment_delete"||op==="note_add"||op==="learning_add"||op==="release"||op==="update"||op==="update_ownership_bypass"||op==="update_audit")}async function prepareLockedItem(params){const typeToFolder=params.typeToFolder??resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(params.pmRoot,params.id,params.settings.id_prefix,params.settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(params.pmRoot,params.id,params.settings.id_prefix,typeToFolder);const lease=await acquireLockLease(params.pmRoot,located.id,params.settings.locks.ttl_seconds,params.author,!!params.force,params.settings.governance.force_required_for_stale_lock,params.settings.locks.wait_ms,{waitPolicy:"progress"}),releaseLock=lease.release;try{const warnings=[],{raw:originalRaw,document}=await readLocatedItem(located,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames,warnings}),assigned=document.metadata.assignee?.trim(),assignedPrincipal=document.metadata.claim_principal?.trim()||assigned,callerPrincipal=resolveClaimPrincipal(params.author),governance=resolveGovernanceKnobs(params.settings);if(assigned&&assignedPrincipal!==callerPrincipal&&!params.force&&!bypassesAssigneeConflict(params.op,params.bypassAssigneeConflict)){if(governance.ownership_enforcement==="strict")throw new PmCliError(`Item ${located.id} is assigned to ${assigned}. Use --force to override.`,EXIT_CODE.CONFLICT);governance.ownership_enforcement==="warn"&&warnings.push(`ownership_warning:assignee_conflict:${located.id}:${assigned}`)}return{typeToFolder,located,originalRaw,document,warnings,releaseLock,lease}}catch(error){throw await releaseLock(),error}}async function commitLockedItemWrite(lease,located,originalRaw,commit){return lease.fence(async()=>{let currentRaw;try{currentRaw=await fs.readFile(located.itemPath,"utf8")}catch(error){if(!isFileMissingError(error))throw error;currentRaw=null}if(currentRaw!==originalRaw)throw new PmCliError(`Item ${located.id} changed after this mutation read it; refusing to overwrite the newer revision. Nothing was written.`,EXIT_CODE.CONFLICT,{code:"stale_revision",item_id:located.id,reason:currentRaw===null?"item_removed":"item_revision_changed",required:"Re-read the item and apply the mutation again; the newer stored revision was kept."});return commit()})}function resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter){if(!serviceWriteOverride.handled||typeof serviceWriteOverride.result!="object"||serviceWriteOverride.result===null)return{effectiveTargetItemPath:targetItemPath,effectiveSerializedAfter:serializedAfter,skipItemWrite:!1};const overrideRecord=serviceWriteOverride.result;return{effectiveTargetItemPath:typeof overrideRecord.target_item_path=="string"&&overrideRecord.target_item_path.trim().length>0?overrideRecord.target_item_path:targetItemPath,effectiveSerializedAfter:typeof overrideRecord.contents=="string"?overrideRecord.contents:serializedAfter,skipItemWrite:overrideRecord.skip_write===!0}}async function resolveItemStoreDeleteOverride(payload){const override=await runActiveServiceOverride("item_store_delete",payload),record=override.handled&&typeof override.result=="object"&&override.result!==null?override.result:{};return{effectiveItemPath:typeof record.item_path=="string"&&record.item_path.trim().length>0?record.item_path:payload.item_path,skipDelete:record.skip_delete===!0,warnings:override.warnings}}async function rollbackMutatedItemWrite(params){if(!params.skipItemWrite){if(params.effectiveTargetItemPath!==params.originalItemPath){await writeFileAtomic(params.originalItemPath,params.originalRaw),await fs.rm(params.effectiveTargetItemPath,{force:!0});return}await writeFileAtomic(params.originalItemPath,params.originalRaw)}}async function mutateItemWithDeferredHistoryContext(params){normalizeHistoryOperationForWrite(params.op);const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:params.op,author:params.author,force:params.force,bypassAssigneeConflict:params.bypassAssigneeConflict,extensionFieldNames:params.extensionFieldNames,typeToFolder:params.typeToFolder}),{typeToFolder,located,originalRaw,document,warnings:parseWarnings,releaseLock,lease}=prepared;try{assertItemMutationPreconditions(params.pmRoot,document);const beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutableDocument=canonicalDocument(structuredClone(document),{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutation=await params.mutate(mutableDocument);if(params.skipNoop===!0&&mutation.changedFields.length===0)return{item:beforeDocument.metadata,body:beforeDocument.body,changedFields:[],warnings:[...parseWarnings,...mutation.warnings??[]]};const historyContext={...params.resolveHistoryContext?.(),...checkpointMutationHistoryContext(params.pmRoot,located.id),...itemMutationPreconditionHistoryContext(params.pmRoot,document)},requiredFormat=Math.max(requiredItemFormatVersion(beforeDocument.metadata),requiredItemFormatVersion(mutableDocument.metadata));assertProjectRuntimeFormatGuard(resolveWorkspaceRoot(params.pmRoot),requiredFormat),requiredFormat>effectiveItemFormatVersion(mutableDocument.metadata)&&(mutableDocument.metadata.pm_format_version=requiredFormat,mutation.changedFields.push("pm_format_version")),mutableDocument.metadata.updated_at=nowIso();const afterDocument=canonicalDocument(mutableDocument,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:params.op,author:params.author,before:beforeDocument,after:afterDocument});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:params.op,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields,sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:params.op}),targetItemFormat="toon",serializedAfter=serializeItemDocument(afterDocument,{format:targetItemFormat,schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),targetItemPath=getItemPath(params.pmRoot,afterDocument.metadata.type,located.id,targetItemFormat,typeToFolder),historyPath=getHistoryPath(params.pmRoot,located.id),committed=await commitLockedItemWrite(lease,located,originalRaw,async()=>{const serviceWriteOverride=await runActiveServiceOverride("item_store_write",{op:params.op,pm_root:params.pmRoot,item_id:located.id,source_item_path:located.itemPath,target_item_path:targetItemPath,history_path:historyPath,item_format:targetItemFormat,before:beforeDocument,after:afterDocument,contents:serializedAfter}),{effectiveTargetItemPath:effectiveTargetItemPath2,effectiveSerializedAfter,skipItemWrite}=resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings2=[];try{skipItemWrite||await writeFileAtomic(effectiveTargetItemPath2,effectiveSerializedAfter),!skipItemWrite&&effectiveTargetItemPath2!==located.itemPath&&await fs.rm(located.itemPath);const entry=createHistoryEntry({nowIso:afterDocument.metadata.updated_at,author:params.author,op:params.op,before:beforeDocument,after:afterDocument,message:params.message,context:workflowPolicy.decisions.length===0?Object.keys(historyContext).length===0?void 0:historyContext:{...historyContext,workflow_policies:workflowPolicy.decisions}});try{await appendHistoryEntry(historyPath,entry)}catch(error){throw await rollbackMutatedItemWrite({skipItemWrite,effectiveTargetItemPath:effectiveTargetItemPath2,originalItemPath:located.itemPath,originalRaw}),error}skipItemWrite||(derivedIndexWarnings2=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder,schema:params.settings.schema,itemPath:effectiveTargetItemPath2,previousItemPath:located.itemPath,document:afterDocument}))}finally{await releaseDerivedIndexLock()}return{derivedIndexWarnings:derivedIndexWarnings2,effectiveTargetItemPath:effectiveTargetItemPath2,overrideWarnings:serviceWriteOverride.warnings}}),{derivedIndexWarnings,effectiveTargetItemPath}=committed;advanceItemMutationPreconditions(params.pmRoot,afterDocument);const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveTargetItemPath,scope:"project",op:params.op,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:`${params.op}:history`,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields})];return recordAfterCommandAffectedItem({id:afterDocument.metadata.id,op:params.op,item_type:afterDocument.metadata.type,previous_status:beforeDocument.metadata.status,status:afterDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,mutation.changedFields),current:projectAfterCommandItemSnapshot(afterDocument.metadata,mutation.changedFields),changed_fields:mutation.changedFields}),{item:afterDocument.metadata,body:afterDocument.body,changedFields:mutation.changedFields,warnings:[...parseWarnings,...mutation.warnings??[],...workflowPolicy.warnings,...historyPolicy.warnings,...committed.overrideWarnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}async function mutateItemWithHistoryContext(params){const{historyContext,...mutationParams}=params;return mutateItemWithDeferredHistoryContext({...mutationParams,resolveHistoryContext:()=>historyContext})}async function mutateItemWithHistoryContextResolver(params){return mutateItemWithDeferredHistoryContext(params)}async function mutateItem(params){return mutateItemWithDeferredHistoryContext(params)}const itemStoreTestOnly={appendWarning,bypassesAssigneeConflict,buildDidYouMeanSuggestions,isErrno};async function deleteItem(params){const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:"delete",author:params.author,force:params.force}),{located,originalRaw,document,warnings:parseWarnings,releaseLock,lease}=prepared;try{assertItemMutationPreconditions(params.pmRoot,document);const extensionFieldNames=resolveActiveExtensionFieldNames(void 0),beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:"delete",author:params.author,before:beforeDocument,after:null,dryRun:params.dryRun});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:"delete",before:beforeDocument,after:null,changed_fields:["deleted"],sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder:prepared.typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:"delete"}),deletionTimestamp=nowIso(),tombstoneDocument=EMPTY_CANONICAL_DOCUMENT,historyEntry=createHistoryEntry({nowIso:deletionTimestamp,author:params.author,op:"delete",before:beforeDocument,after:tombstoneDocument,message:params.message,context:workflowPolicy.decisions.length===0?void 0:{workflow_policies:workflowPolicy.decisions}}),historyPath=getHistoryPath(params.pmRoot,located.id),runDeleteOverride=()=>resolveItemStoreDeleteOverride({op:"delete",pm_root:params.pmRoot,item_id:located.id,item_path:located.itemPath,history_path:historyPath,before:beforeDocument});if(params.dryRun===!0){const preview=await runDeleteOverride();return{item:beforeDocument.metadata,changedFields:["deleted"],targetPath:preview.effectiveItemPath,warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...preview.warnings]}}const committed=await commitLockedItemWrite(lease,located,originalRaw,async()=>{const{effectiveItemPath:effectiveItemPath2,skipDelete,warnings}=await runDeleteOverride(),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings2=[];try{skipDelete||await fs.rm(effectiveItemPath2);try{await appendHistoryEntry(historyPath,historyEntry)}catch(error){throw skipDelete||await writeFileAtomic(effectiveItemPath2,originalRaw),error}skipDelete||(derivedIndexWarnings2=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder:prepared.typeToFolder,schema:params.settings.schema,itemPath:effectiveItemPath2,document:null}))}finally{await releaseDerivedIndexLock()}return{derivedIndexWarnings:derivedIndexWarnings2,effectiveItemPath:effectiveItemPath2,overrideWarnings:warnings}}),{derivedIndexWarnings,effectiveItemPath}=committed,hookWarnings=[...await runActiveOnWriteHooks({path:effectiveItemPath,scope:"project",op:"delete",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:"delete:history",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]})];return recordAfterCommandAffectedItem({id:beforeDocument.metadata.id,op:"delete",item_type:beforeDocument.metadata.type,previous_status:beforeDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,Object.keys(beforeDocument.metadata)),changed_fields:["deleted"]}),{item:beforeDocument.metadata,changedFields:["deleted"],warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...committed.overrideWarnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}export{buildItemNotFoundError,createMutationGuardSdk,deleteItem,itemStoreTestOnly,listAllItemMetadata,listAllItemMetadataLight,listAllItemMetadataWithBody,locateItem,mutateItem,mutateItemWithHistoryContext,mutateItemWithHistoryContextResolver,readLocatedItem,readLocatedItemSnapshot};
|
|
2
2
|
//# sourceMappingURL=item-store.js.map
|